mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-28 01:43:47 -04:00
Merge tag 'amd-drm-next-7.3-2026-08-06' of https://gitlab.freedesktop.org/agd5f/linux into drm-next
amd-drm-next-7.3-2026-08-06: amdgpu: - JPEG queue reset fixes - GC 12 fix - GMC 12.1 fixes - Lockdep false positive fix - Userq fixes - Bounds checking fixes - Devcoredump fixes - DCN 2.0.1 fix - Aperture mapping fix - DC avmute fix - DC self refresh fix - RAS updates - SMU 15 updates - SMU PPT updates - SMU 14 fixes - Initial DCN 6.0.0 support - GC 6 soft reset rework - Display bounds checking fixes - FRL fixes - VRR fixes - More display KUnit tests - Refactor DC stream validation - DCN 3.5.1 fixes - DCN 3.2 fixes - DC CRC fixes - MES 12.0 fixes amdkfd: - SVM fixes - MES updates radeon: - Performance regression fix Signed-off-by: Dave Airlie <airlied@redhat.com> From: Alex Deucher <alexander.deucher@amd.com> Link: https://patch.msgid.link/20260806213106.994528-1-alexander.deucher@amd.com
This commit is contained in:
@@ -42,6 +42,26 @@
|
||||
#include "amdgpu_ras.h"
|
||||
#include "amdgpu_hmm.h"
|
||||
|
||||
/*
|
||||
* Maximum IB length (dwords) for rings whose emit_ib packet format
|
||||
* documents a 20-bit size field.
|
||||
*/
|
||||
#define AMDGPU_GFX_SDMA_IB_PACKET_SIZE_MAX_DW 0xFFFFF
|
||||
#define AMDGPU_MM_IB_PACKET_SIZE_MAX_DW 0x7FFFF0
|
||||
|
||||
static u32 amdgpu_cs_ib_packet_size_max_dw(enum amdgpu_ring_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case AMDGPU_RING_TYPE_GFX:
|
||||
case AMDGPU_RING_TYPE_COMPUTE:
|
||||
case AMDGPU_RING_TYPE_SDMA:
|
||||
case AMDGPU_RING_TYPE_VPE:
|
||||
return AMDGPU_GFX_SDMA_IB_PACKET_SIZE_MAX_DW;
|
||||
default:
|
||||
return AMDGPU_MM_IB_PACKET_SIZE_MAX_DW;
|
||||
}
|
||||
}
|
||||
|
||||
static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p,
|
||||
struct amdgpu_device *adev,
|
||||
struct drm_file *filp,
|
||||
@@ -340,7 +360,6 @@ static int amdgpu_cs_p2_ib(struct amdgpu_cs_parser *p,
|
||||
|
||||
job = p->jobs[r];
|
||||
ring = amdgpu_job_ring(job);
|
||||
ib = &job->ibs[job->num_ibs++];
|
||||
|
||||
/* submissions to kernel queues are disabled */
|
||||
if (ring->no_user_submission)
|
||||
@@ -369,6 +388,12 @@ static int amdgpu_cs_p2_ib(struct amdgpu_cs_parser *p,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (chunk_ib->ib_bytes / 4 >
|
||||
amdgpu_cs_ib_packet_size_max_dw(ring->funcs->type))
|
||||
return -EINVAL;
|
||||
|
||||
ib = &job->ibs[job->num_ibs++];
|
||||
|
||||
if (chunk_ib->flags & AMDGPU_IB_FLAG_PREAMBLE)
|
||||
job->preamble_status |= AMDGPU_PREAMBLE_IB_PRESENT;
|
||||
|
||||
|
||||
@@ -343,7 +343,7 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
|
||||
struct amdgpu_ip_block *ip_block;
|
||||
struct amdgpu_ring *ring;
|
||||
int ver, i, j;
|
||||
u32 ring_idx, off;
|
||||
u32 ring_idx;
|
||||
bool sizing_pass;
|
||||
|
||||
sizing_pass = buffer == NULL;
|
||||
@@ -443,7 +443,6 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
|
||||
for (i = 0; i < coredump->num_rings; i++) {
|
||||
ring_idx = coredump->rings[i].ring_index;
|
||||
ring = coredump->adev->rings[ring_idx];
|
||||
off = coredump->rings[i].offset;
|
||||
|
||||
drm_printf(&p, "ring name: %s\n", ring->name);
|
||||
drm_printf(&p, "Rptr: 0x%llx Wptr: 0x%llx RB mask: %x\n",
|
||||
@@ -452,12 +451,18 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
|
||||
ring->buf_mask);
|
||||
drm_printf(&p, "Ring size in dwords: %d\n",
|
||||
ring->ring_size / 4);
|
||||
|
||||
if (!coredump->rings[i].ring_dw) {
|
||||
drm_printf(&p, "Ring contents unavailable\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
drm_printf(&p, "Ring contents\n");
|
||||
drm_printf(&p, "Offset \t Value\n");
|
||||
|
||||
for (j = 0; j < ring->ring_size; j += 4)
|
||||
drm_printf(&p, "0x%x \t 0x%x\n", j,
|
||||
coredump->rings_dw[off + j / 4]);
|
||||
coredump->rings[i].ring_dw[j / 4]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,10 +503,12 @@ amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count,
|
||||
static void amdgpu_devcoredump_free(void *data)
|
||||
{
|
||||
struct amdgpu_coredump_info *coredump = data;
|
||||
u32 i;
|
||||
|
||||
kvfree(coredump->formatted);
|
||||
for (i = 0; i < coredump->num_rings; i++)
|
||||
kvfree(coredump->rings[i].ring_dw);
|
||||
kvfree(coredump->rings);
|
||||
kvfree(coredump->rings_dw);
|
||||
kvfree(data);
|
||||
}
|
||||
|
||||
@@ -543,9 +550,9 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
struct amdgpu_coredump_info *coredump;
|
||||
size_t size = sizeof(*coredump);
|
||||
struct drm_sched_job *s_job;
|
||||
u64 total_ring_size, ring_count;
|
||||
u64 ring_count;
|
||||
struct amdgpu_ring *ring;
|
||||
int i, off, idx;
|
||||
int i, idx;
|
||||
|
||||
/* No need to generate a new coredump if there's one in progress already. */
|
||||
if (work_busy(&adev->coredump_work))
|
||||
@@ -554,7 +561,7 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
if (job && job->pasid)
|
||||
size += sizeof(struct amdgpu_coredump_ib_info) * job->num_ibs;
|
||||
|
||||
coredump = kzalloc(size, GFP_NOWAIT);
|
||||
coredump = kvzalloc(size, GFP_NOWAIT);
|
||||
if (!coredump)
|
||||
return;
|
||||
|
||||
@@ -585,7 +592,6 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
|
||||
/* Dump ring content if memory allocation succeeds. */
|
||||
ring_count = 0;
|
||||
total_ring_size = 0;
|
||||
for (i = 0; i < adev->num_rings; i++) {
|
||||
ring = adev->rings[i];
|
||||
|
||||
@@ -594,34 +600,34 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check,
|
||||
coredump->ring != ring)
|
||||
continue;
|
||||
|
||||
total_ring_size += ring->ring_size;
|
||||
ring_count++;
|
||||
}
|
||||
coredump->rings_dw = kzalloc(total_ring_size, GFP_NOWAIT);
|
||||
coredump->rings = kcalloc(ring_count, sizeof(struct amdgpu_coredump_ring), GFP_NOWAIT);
|
||||
if (coredump->rings && coredump->rings_dw) {
|
||||
for (i = 0, off = 0, idx = 0; i < adev->num_rings && idx < ring_count; i++) {
|
||||
if (ring_count)
|
||||
coredump->rings = kvcalloc(ring_count,
|
||||
sizeof(struct amdgpu_coredump_ring),
|
||||
GFP_NOWAIT);
|
||||
if (coredump->rings) {
|
||||
for (i = 0, idx = 0; i < adev->num_rings && idx < ring_count; i++) {
|
||||
struct amdgpu_coredump_ring *cdump_ring;
|
||||
|
||||
ring = adev->rings[i];
|
||||
|
||||
if (atomic_read(&ring->fence_drv.last_seq) == ring->fence_drv.sync_seq &&
|
||||
coredump->ring != ring)
|
||||
continue;
|
||||
|
||||
coredump->rings[idx].ring_index = ring->idx;
|
||||
coredump->rings[idx].rptr = amdgpu_ring_get_rptr(ring);
|
||||
coredump->rings[idx].wptr = amdgpu_ring_get_wptr(ring);
|
||||
coredump->rings[idx].offset = off;
|
||||
cdump_ring = &coredump->rings[idx];
|
||||
|
||||
memcpy(&coredump->rings_dw[off], ring->ring, ring->ring_size);
|
||||
off += ring->ring_size / 4;
|
||||
cdump_ring->ring_dw = kvzalloc(ring->ring_size, GFP_NOWAIT);
|
||||
if (cdump_ring->ring_dw)
|
||||
memcpy(cdump_ring->ring_dw, ring->ring, ring->ring_size);
|
||||
|
||||
cdump_ring->ring_index = ring->idx;
|
||||
cdump_ring->rptr = amdgpu_ring_get_rptr(ring);
|
||||
cdump_ring->wptr = amdgpu_ring_get_wptr(ring);
|
||||
idx++;
|
||||
}
|
||||
coredump->num_rings = idx;
|
||||
} else {
|
||||
kvfree(coredump->rings_dw);
|
||||
kvfree(coredump->rings);
|
||||
coredump->rings_dw = NULL;
|
||||
coredump->rings = NULL;
|
||||
}
|
||||
|
||||
coredump->adev = adev;
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
struct amdgpu_coredump_ring {
|
||||
u64 rptr;
|
||||
u64 wptr;
|
||||
u32 *ring_dw;
|
||||
u32 ring_index;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
struct amdgpu_coredump_ib_info {
|
||||
@@ -53,7 +53,6 @@ struct amdgpu_coredump_info {
|
||||
struct amdgpu_ring *ring;
|
||||
|
||||
struct amdgpu_coredump_ring *rings;
|
||||
u32 *rings_dw;
|
||||
u32 num_rings;
|
||||
|
||||
/* Readable form of coredevdump, generate once to speed up
|
||||
|
||||
@@ -4185,6 +4185,8 @@ static void amdgpu_device_unmap_mmio(struct amdgpu_device *adev)
|
||||
|
||||
iounmap(adev->rmmio);
|
||||
adev->rmmio = NULL;
|
||||
if (adev->mman.aper_base_kaddr)
|
||||
iounmap(adev->mman.aper_base_kaddr);
|
||||
adev->mman.aper_base_kaddr = NULL;
|
||||
|
||||
/* Memory manager related */
|
||||
|
||||
@@ -334,6 +334,19 @@ static int amdgpu_discovery_get_tmr_info(struct amdgpu_device *adev,
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if (adev->discovery.offset) {
|
||||
u32 signature;
|
||||
|
||||
/* If VRAM holds a valid discovery signature at the default
|
||||
* discovery offset, use it as-is.
|
||||
*/
|
||||
amdgpu_device_vram_access(adev, adev->discovery.offset,
|
||||
&signature, sizeof(signature),
|
||||
false);
|
||||
if (le32_to_cpu(signature) == BINARY_SIGNATURE)
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmr_size = RREG32(mmDRIVER_SCRATCH_2);
|
||||
if (tmr_size) {
|
||||
/* It's preferred to transition to PSP mailbox reg interface
|
||||
@@ -2658,6 +2671,7 @@ static int amdgpu_discovery_set_display_ip_blocks(struct amdgpu_device *adev)
|
||||
case IP_VERSION(4, 1, 0):
|
||||
case IP_VERSION(4, 2, 0):
|
||||
case IP_VERSION(4, 2, 1):
|
||||
case IP_VERSION(6, 0, 0):
|
||||
/* TODO: Fix IP version. DC code expects version 4.0.1 */
|
||||
if (adev->ip_versions[DCE_HWIP][0] == IP_VERSION(4, 1, 0))
|
||||
adev->ip_versions[DCE_HWIP][0] = IP_VERSION(4, 0, 1);
|
||||
|
||||
@@ -866,7 +866,8 @@ int amdgpu_gfx_enable_kgq(struct amdgpu_device *adev, int xcc_id)
|
||||
* @queue_id: queue ID of the faulty ring
|
||||
*
|
||||
* This function handles privileged instruction faults by identifying
|
||||
* the faulty ring (gfx or compute) and triggering a scheduler fault
|
||||
* the faulty ring (gfx or compute) and triggering a scheduler fault, or by
|
||||
* recovering the faulting user queue.
|
||||
*/
|
||||
void amdgpu_gfx_handle_priv_fault(struct amdgpu_device *adev,
|
||||
struct amdgpu_iv_entry *entry,
|
||||
@@ -901,12 +902,25 @@ void amdgpu_gfx_handle_priv_fault(struct amdgpu_device *adev,
|
||||
}
|
||||
}
|
||||
|
||||
/* No KQ matched: the faulting slot belongs to a user queue. */
|
||||
if (adev->gfx.disable_uq)
|
||||
return;
|
||||
|
||||
doorbell_offset = entry->src_data[0] & AMDGPU_CTXID0_DOORBELL_ID_MASK;
|
||||
|
||||
/* No KQ matched: HW slot is a MES-scheduled user queue. */
|
||||
if (adev->enable_mes && doorbell_offset)
|
||||
/*
|
||||
* A compute user-queue fault IV carries the doorbell offset, so reset
|
||||
* the queue directly from it. A gfx user-queue fault is raised by the
|
||||
* ME and carries only the HW slot (no doorbell); record the slot and
|
||||
* let the worker read the doorbell back from the HQD.
|
||||
*/
|
||||
if (doorbell_offset) {
|
||||
amdgpu_userq_process_reset_irq(adev, entry->pasid,
|
||||
doorbell_offset);
|
||||
} else {
|
||||
set_bit(pipe_id | (queue_id << 2), &adev->gfx.userq_priv_fault_slots);
|
||||
schedule_work(&adev->gfx.userq_priv_fault_work);
|
||||
}
|
||||
}
|
||||
|
||||
static void amdgpu_gfx_do_off_ctrl(struct amdgpu_device *adev, bool enable,
|
||||
|
||||
@@ -535,6 +535,9 @@ struct amdgpu_gfx {
|
||||
struct mutex userq_sch_mutex;
|
||||
u64 userq_sch_req_count[MAX_XCP];
|
||||
bool userq_sch_inactive[MAX_XCP];
|
||||
/* atomic bitmap of faulted gfx UQ slots (index = pipe | queue << 2) */
|
||||
unsigned long userq_priv_fault_slots;
|
||||
struct work_struct userq_priv_fault_work;
|
||||
unsigned long enforce_isolation_jiffies[MAX_XCP];
|
||||
unsigned long enforce_isolation_time[MAX_XCP];
|
||||
|
||||
|
||||
@@ -628,16 +628,6 @@ int amdgpu_gmc_ras_sw_init(struct amdgpu_device *adev)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amdgpu_gmc_ras_late_init(struct amdgpu_device *adev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void amdgpu_gmc_ras_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -438,8 +438,6 @@ int amdgpu_gmc_handle_retry_fault(struct amdgpu_device *adev,
|
||||
u32 node_id,
|
||||
bool write_fault);
|
||||
int amdgpu_gmc_ras_sw_init(struct amdgpu_device *adev);
|
||||
int amdgpu_gmc_ras_late_init(struct amdgpu_device *adev);
|
||||
void amdgpu_gmc_ras_fini(struct amdgpu_device *adev);
|
||||
int amdgpu_gmc_allocate_vm_inv_eng(struct amdgpu_device *adev);
|
||||
void amdgpu_gmc_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid,
|
||||
uint32_t vmhub, uint32_t flush_type);
|
||||
|
||||
@@ -135,6 +135,21 @@ int amdgpu_lockdep_init(void)
|
||||
lockdep_set_class(&locks->srbm_mutex, &amdgpu_srbm_lock_key);
|
||||
lockdep_set_class(&locks->grbm_idx_mutex, &amdgpu_grbm_lock_key);
|
||||
lockdep_set_class(&locks->mmio_idx_lock, &amdgpu_mmio_lock_key);
|
||||
|
||||
/*
|
||||
* Register fs_reclaim lock class FIRST, before taking any locks.
|
||||
*
|
||||
* This acquire/release pair does NOT create a static lockdep edge
|
||||
* (no locks are held between acquire and release). It only registers
|
||||
* the fs_reclaim lock class with lockdep.
|
||||
*
|
||||
* The actual fs_reclaim -> notifier_lock dependency is established at
|
||||
* RUNTIME when memory reclaim invokes MMU notifiers:
|
||||
* fs_reclaim (held by reclaim) -> notifier_lock (acquired in callback)
|
||||
*/
|
||||
fs_reclaim_acquire(GFP_KERNEL);
|
||||
fs_reclaim_release(GFP_KERNEL);
|
||||
|
||||
/*
|
||||
* Take locks in the correct order to train lockdep.
|
||||
* This establishes the dependency chain.
|
||||
@@ -154,11 +169,6 @@ int amdgpu_lockdep_init(void)
|
||||
|
||||
/* Level 6: Reset control lock */
|
||||
mutex_lock(&locks->reset_lock);
|
||||
/*
|
||||
* Mark potential memory reclaim boundary.
|
||||
* GPU operations might trigger memory allocation/reclaim.
|
||||
*/
|
||||
fs_reclaim_acquire(GFP_KERNEL);
|
||||
|
||||
/* Level 7: SRBM register access */
|
||||
mutex_lock(&locks->srbm_mutex);
|
||||
@@ -176,7 +186,6 @@ int amdgpu_lockdep_init(void)
|
||||
spin_unlock_irqrestore(&locks->mmio_idx_lock, flags);
|
||||
mutex_unlock(&locks->grbm_idx_mutex);
|
||||
mutex_unlock(&locks->srbm_mutex);
|
||||
fs_reclaim_release(GFP_KERNEL);
|
||||
|
||||
mutex_unlock(&locks->reset_lock);
|
||||
up_read(&reset_domain->sem);
|
||||
|
||||
@@ -308,8 +308,12 @@ void amdgpu_mes_fini(struct amdgpu_device *adev)
|
||||
|
||||
amdgpu_mes_doorbell_free(adev);
|
||||
|
||||
if (adev->mes.use_rs64mem)
|
||||
amdgpu_mes_rs64mem_fini(&adev->mes);
|
||||
|
||||
ida_destroy(&adev->mes.doorbell_ida);
|
||||
mutex_destroy(&adev->mes.mutex_hidden);
|
||||
|
||||
}
|
||||
|
||||
int amdgpu_mes_suspend(struct amdgpu_device *adev, u32 xcc_id)
|
||||
@@ -1040,13 +1044,13 @@ int amdgpu_mes_rs64mem_setup_bitmaps(struct amdgpu_mes *mes)
|
||||
* amdgpu_mes_alloc_proc_ctx_index - allocate a process context slot
|
||||
*
|
||||
* @mes: MES instance
|
||||
* @queue: Usermode queue receiving the allocated process context index
|
||||
* @index: the allocated process context index
|
||||
*
|
||||
* Returns 0 on success, -ENOSPC if all slots are used, or
|
||||
* -EOPNOTSUPP if RS64 local memory is unavailable.
|
||||
*/
|
||||
int amdgpu_mes_alloc_proc_ctx_index(struct amdgpu_mes *mes,
|
||||
struct amdgpu_usermode_queue *queue)
|
||||
uint32_t *index)
|
||||
{
|
||||
unsigned long bit;
|
||||
|
||||
@@ -1061,7 +1065,7 @@ int amdgpu_mes_alloc_proc_ctx_index(struct amdgpu_mes *mes,
|
||||
return -ENOSPC;
|
||||
}
|
||||
set_bit(bit, mes->proc_ctx_bitmap);
|
||||
queue->proc_ctx_array_index = (uint32_t)bit;
|
||||
*index = (uint32_t)bit;
|
||||
amdgpu_mes_unlock(mes);
|
||||
|
||||
return 0;
|
||||
@@ -1071,18 +1075,18 @@ int amdgpu_mes_alloc_proc_ctx_index(struct amdgpu_mes *mes,
|
||||
* amdgpu_mes_free_proc_ctx_index - free a process context slot
|
||||
*
|
||||
* @mes: MES instance
|
||||
* @queue: Usermode queue whose process context index is released
|
||||
* @index: process context index is released
|
||||
*/
|
||||
void amdgpu_mes_free_proc_ctx_index(struct amdgpu_mes *mes,
|
||||
struct amdgpu_usermode_queue *queue)
|
||||
uint32_t index)
|
||||
{
|
||||
if (!mes->use_rs64mem || !mes->proc_ctx_bitmap)
|
||||
return;
|
||||
if (queue->proc_ctx_array_index >= mes->proc_ctx_array_size)
|
||||
if (index >= mes->proc_ctx_array_size)
|
||||
return;
|
||||
|
||||
amdgpu_mes_lock(mes);
|
||||
clear_bit(queue->proc_ctx_array_index, mes->proc_ctx_bitmap);
|
||||
clear_bit(index, mes->proc_ctx_bitmap);
|
||||
amdgpu_mes_unlock(mes);
|
||||
}
|
||||
|
||||
@@ -1090,13 +1094,13 @@ void amdgpu_mes_free_proc_ctx_index(struct amdgpu_mes *mes,
|
||||
* amdgpu_mes_alloc_gang_ctx_index - allocate a gang context slot
|
||||
*
|
||||
* @mes: MES instance
|
||||
* @queue: Usermode queue receiving the allocated gang context index
|
||||
* @index: the allocated gang context index
|
||||
*
|
||||
* Returns 0 on success, -ENOSPC if all slots are used, or
|
||||
* -EOPNOTSUPP if RS64 local memory is unavailable.
|
||||
*/
|
||||
int amdgpu_mes_alloc_gang_ctx_index(struct amdgpu_mes *mes,
|
||||
struct amdgpu_usermode_queue *queue)
|
||||
uint32_t *index)
|
||||
{
|
||||
unsigned long bit;
|
||||
|
||||
@@ -1111,7 +1115,7 @@ int amdgpu_mes_alloc_gang_ctx_index(struct amdgpu_mes *mes,
|
||||
return -ENOSPC;
|
||||
}
|
||||
set_bit(bit, mes->gang_ctx_bitmap);
|
||||
queue->gang_ctx_array_index = bit;
|
||||
*index = bit;
|
||||
amdgpu_mes_unlock(mes);
|
||||
|
||||
return 0;
|
||||
@@ -1121,18 +1125,18 @@ int amdgpu_mes_alloc_gang_ctx_index(struct amdgpu_mes *mes,
|
||||
* amdgpu_mes_free_gang_ctx_index - free a gang context slot
|
||||
*
|
||||
* @mes: MES instance
|
||||
* @queue: Usermode queue whose gang context index is released
|
||||
* @index: gang context index is released
|
||||
*/
|
||||
void amdgpu_mes_free_gang_ctx_index(struct amdgpu_mes *mes,
|
||||
struct amdgpu_usermode_queue *queue)
|
||||
uint32_t index)
|
||||
{
|
||||
if (!mes->use_rs64mem || !mes->gang_ctx_bitmap)
|
||||
return;
|
||||
if (queue->gang_ctx_array_index >= mes->gang_ctx_array_size)
|
||||
if (index >= mes->gang_ctx_array_size)
|
||||
return;
|
||||
|
||||
amdgpu_mes_lock(mes);
|
||||
clear_bit(queue->gang_ctx_array_index, mes->gang_ctx_bitmap);
|
||||
clear_bit(index, mes->gang_ctx_bitmap);
|
||||
amdgpu_mes_unlock(mes);
|
||||
}
|
||||
|
||||
|
||||
@@ -636,11 +636,11 @@ int amdgpu_mes_rs64mem_init(struct amdgpu_mes *mes);
|
||||
void amdgpu_mes_rs64mem_fini(struct amdgpu_mes *mes);
|
||||
int amdgpu_mes_rs64mem_setup_bitmaps(struct amdgpu_mes *mes);
|
||||
int amdgpu_mes_alloc_proc_ctx_index(struct amdgpu_mes *mes,
|
||||
struct amdgpu_usermode_queue *queue);
|
||||
uint32_t *index);
|
||||
void amdgpu_mes_free_proc_ctx_index(struct amdgpu_mes *mes,
|
||||
struct amdgpu_usermode_queue *queue);
|
||||
uint32_t index);
|
||||
int amdgpu_mes_alloc_gang_ctx_index(struct amdgpu_mes *mes,
|
||||
struct amdgpu_usermode_queue *queue);
|
||||
uint32_t *index);
|
||||
void amdgpu_mes_free_gang_ctx_index(struct amdgpu_mes *mes,
|
||||
struct amdgpu_usermode_queue *queue);
|
||||
uint32_t index);
|
||||
#endif /* __AMDGPU_MES_H__ */
|
||||
|
||||
@@ -2751,7 +2751,8 @@ static void amdgpu_ras_do_recovery(struct work_struct *work)
|
||||
}
|
||||
|
||||
if (amdgpu_ras_get_error_query_mode(adev, &error_query_mode)) {
|
||||
if (error_query_mode == AMDGPU_RAS_FIRMWARE_ERROR_QUERY) {
|
||||
if (error_query_mode == AMDGPU_RAS_FIRMWARE_ERROR_QUERY &&
|
||||
(ras->gpu_reset_flags & AMDGPU_RAS_GPU_RESET_MODE1_RESET)) {
|
||||
/* wait 500ms to ensure pmfw polling mca bank info done */
|
||||
msleep(500);
|
||||
}
|
||||
@@ -4422,6 +4423,10 @@ bool amdgpu_ras_get_error_query_mode(struct amdgpu_device *adev,
|
||||
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
*error_query_mode = AMDGPU_RAS_VIRT_ERROR_COUNT_QUERY;
|
||||
} else if (amdgpu_uniras_enabled(adev)) {
|
||||
*error_query_mode = amdgpu_ras_mgr_get_debug_mode(adev) ?
|
||||
AMDGPU_RAS_DIRECT_ERROR_QUERY :
|
||||
AMDGPU_RAS_FIRMWARE_ERROR_QUERY;
|
||||
} else {
|
||||
*error_query_mode = AMDGPU_RAS_DIRECT_ERROR_QUERY;
|
||||
}
|
||||
|
||||
@@ -2139,23 +2139,17 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
|
||||
/* Change the size here instead of the init above so only lpfn is affected */
|
||||
amdgpu_ttm_disable_buffer_funcs(adev);
|
||||
#ifdef CONFIG_64BIT
|
||||
if (adev->gmc.xgmi.connected_to_cpu) {
|
||||
void *kaddr = devm_memremap(adev->dev, adev->gmc.aper_base,
|
||||
adev->gmc.visible_vram_size,
|
||||
MEMREMAP_WB);
|
||||
if (IS_ERR(kaddr))
|
||||
return PTR_ERR(kaddr);
|
||||
adev->mman.aper_base_kaddr = (__force void __iomem *)kaddr;
|
||||
} else if (adev->gmc.is_app_apu) {
|
||||
#ifdef CONFIG_X86
|
||||
if (adev->gmc.xgmi.connected_to_cpu)
|
||||
adev->mman.aper_base_kaddr = ioremap_cache(adev->gmc.aper_base,
|
||||
adev->gmc.visible_vram_size);
|
||||
else if (adev->gmc.is_app_apu)
|
||||
DRM_DEBUG_DRIVER(
|
||||
"No need to ioremap when real vram size is 0\n");
|
||||
} else {
|
||||
adev->mman.aper_base_kaddr = devm_ioremap_wc(adev->dev,
|
||||
adev->gmc.aper_base,
|
||||
adev->gmc.visible_vram_size);
|
||||
if (!adev->mman.aper_base_kaddr)
|
||||
return -ENOMEM;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
adev->mman.aper_base_kaddr = ioremap_wc(adev->gmc.aper_base,
|
||||
adev->gmc.visible_vram_size);
|
||||
#endif
|
||||
|
||||
amdgpu_ttm_init_vram_resv_regions(adev);
|
||||
@@ -2306,7 +2300,10 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW_VRAM_USAGE);
|
||||
amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_DRV_VRAM_USAGE);
|
||||
|
||||
adev->mman.aper_base_kaddr = NULL;
|
||||
if (adev->mman.aper_base_kaddr) {
|
||||
iounmap(adev->mman.aper_base_kaddr);
|
||||
adev->mman.aper_base_kaddr = NULL;
|
||||
}
|
||||
|
||||
if (!adev->gmc.is_app_apu)
|
||||
amdgpu_vram_mgr_fini(adev);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <drm/drm_auth.h>
|
||||
#include <drm/drm_exec.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <drm/drm_drv.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
@@ -238,24 +239,30 @@ int amdgpu_userq_input_va_validate(struct amdgpu_device *adev,
|
||||
{
|
||||
struct amdgpu_bo_va_mapping *va_map;
|
||||
struct amdgpu_vm *vm = queue->vm;
|
||||
u64 user_addr;
|
||||
u64 size;
|
||||
u64 start_addr;
|
||||
u64 end_addr;
|
||||
u64 start_page;
|
||||
|
||||
/* Caller must hold vm->root.bo reservation */
|
||||
dma_resv_assert_held(queue->vm->root.bo->tbo.base.resv);
|
||||
|
||||
user_addr = (addr & AMDGPU_GMC_HOLE_MASK) >> AMDGPU_GPU_PAGE_SHIFT;
|
||||
size = expected_size >> AMDGPU_GPU_PAGE_SHIFT;
|
||||
if (!expected_size)
|
||||
return -EINVAL;
|
||||
|
||||
va_map = amdgpu_vm_bo_lookup_mapping(vm, user_addr);
|
||||
start_addr = addr & AMDGPU_GMC_HOLE_MASK;
|
||||
if (check_add_overflow(start_addr, expected_size - 1, &end_addr))
|
||||
return -EINVAL;
|
||||
|
||||
start_page = start_addr >> AMDGPU_GPU_PAGE_SHIFT;
|
||||
|
||||
va_map = amdgpu_vm_bo_lookup_mapping(vm, start_page);
|
||||
if (!va_map)
|
||||
return -EINVAL;
|
||||
|
||||
/* Only validate the userq whether resident in the VM mapping range */
|
||||
if (user_addr >= va_map->start &&
|
||||
va_map->last - user_addr + 1 >= size) {
|
||||
/* Lookup guarantees start_page is mapped; ensure full span is covered. */
|
||||
if ((end_addr >> AMDGPU_GPU_PAGE_SHIFT) <= va_map->last) {
|
||||
va_map->bo_va->userq_va_mapped = true;
|
||||
*va_out = user_addr;
|
||||
*va_out = start_page;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -738,7 +745,12 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
|
||||
if (!adev->userq_halt_for_enforce_isolation ||
|
||||
((queue->queue_type != AMDGPU_HW_IP_GFX) &&
|
||||
(queue->queue_type != AMDGPU_HW_IP_COMPUTE))) {
|
||||
/* Serialize the map against an in-progress GPU reset (MES is
|
||||
* unresponsive during recovery), matching amdgpu_userq_cleanup().
|
||||
*/
|
||||
down_read(&adev->reset_domain->sem);
|
||||
r = amdgpu_userq_map_helper(queue);
|
||||
up_read(&adev->reset_domain->sem);
|
||||
if (r) {
|
||||
drm_file_err(uq_mgr->file, "Failed to map Queue\n");
|
||||
trace_amdgpu_userq_create_end(queue, r);
|
||||
@@ -1250,6 +1262,7 @@ int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *f
|
||||
xa_init_flags(&userq_mgr->userq_xa, XA_FLAGS_ALLOC);
|
||||
userq_mgr->adev = adev;
|
||||
userq_mgr->file = file_priv;
|
||||
userq_mgr->proc_ctx_allocated = false;
|
||||
mutex_init(&userq_mgr->proc_ctx_lock);
|
||||
|
||||
INIT_DELAYED_WORK(&userq_mgr->resume_work, amdgpu_userq_restore_worker);
|
||||
@@ -1278,6 +1291,7 @@ void amdgpu_userq_mgr_cancel_resume(struct amdgpu_userq_mgr *userq_mgr)
|
||||
|
||||
void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr)
|
||||
{
|
||||
struct amdgpu_mes *mes = &userq_mgr->adev->mes;
|
||||
struct amdgpu_usermode_queue *queue;
|
||||
unsigned long queue_id = 0;
|
||||
|
||||
@@ -1304,6 +1318,10 @@ void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr)
|
||||
*/
|
||||
cancel_work_sync(&userq_mgr->reset_work);
|
||||
|
||||
if (userq_mgr->proc_ctx_allocated) {
|
||||
amdgpu_mes_free_proc_ctx_index(mes, userq_mgr->proc_ctx_array_index);
|
||||
userq_mgr->proc_ctx_allocated = false;
|
||||
}
|
||||
amdgpu_bo_free_kernel(&userq_mgr->proc_ctx_obj.obj,
|
||||
&userq_mgr->proc_ctx_obj.gpu_addr,
|
||||
&userq_mgr->proc_ctx_obj.cpu_ptr);
|
||||
|
||||
@@ -101,7 +101,6 @@ struct amdgpu_usermode_queue {
|
||||
u64 va_array[6];
|
||||
} userq_vas;
|
||||
|
||||
uint32_t proc_ctx_array_index;
|
||||
uint32_t gang_ctx_array_index;
|
||||
};
|
||||
|
||||
@@ -133,6 +132,8 @@ struct amdgpu_userq_mgr {
|
||||
struct mutex proc_ctx_lock;
|
||||
struct amdgpu_userq_obj proc_ctx_obj;
|
||||
|
||||
bool proc_ctx_allocated;
|
||||
uint32_t proc_ctx_array_index;
|
||||
/**
|
||||
* @reset_work:
|
||||
*
|
||||
|
||||
@@ -362,6 +362,7 @@ static void gfx_v11_0_ring_invalidate_tlbs(struct amdgpu_ring *ring,
|
||||
bool all_hub, uint8_t dst_sel);
|
||||
static void gfx_v11_0_set_safe_mode(struct amdgpu_device *adev, int xcc_id);
|
||||
static void gfx_v11_0_unset_safe_mode(struct amdgpu_device *adev, int xcc_id);
|
||||
static void gfx_v11_0_userq_priv_fault_work(struct work_struct *work);
|
||||
static void gfx_v11_0_update_perf_clk(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
|
||||
@@ -1932,6 +1933,8 @@ static int gfx_v11_0_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
|
||||
mutex_init(&adev->gfx.mec.reset_mutex);
|
||||
|
||||
INIT_WORK(&adev->gfx.userq_priv_fault_work, gfx_v11_0_userq_priv_fault_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1969,6 +1972,8 @@ static int gfx_v11_0_sw_fini(struct amdgpu_ip_block *ip_block)
|
||||
int i;
|
||||
struct amdgpu_device *adev = ip_block->adev;
|
||||
|
||||
cancel_work_sync(&adev->gfx.userq_priv_fault_work);
|
||||
|
||||
for (i = 0; i < adev->gfx.num_gfx_rings; i++)
|
||||
amdgpu_ring_fini(&adev->gfx.gfx_ring[i]);
|
||||
for (i = 0; i < adev->gfx.num_compute_rings; i++)
|
||||
@@ -6711,6 +6716,40 @@ static int gfx_v11_0_set_priv_inst_fault_state(struct amdgpu_device *adev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A gfx exception IV carries no doorbell. For each faulted slot, read the
|
||||
* doorbell back from the HQD (left in place by the fatal fault), look up the
|
||||
* user queue and kick its per-queue reset.
|
||||
*/
|
||||
static void gfx_v11_0_userq_priv_fault_work(struct work_struct *work)
|
||||
{
|
||||
struct amdgpu_device *adev =
|
||||
container_of(work, struct amdgpu_device, gfx.userq_priv_fault_work);
|
||||
unsigned long slots = xchg(&adev->gfx.userq_priv_fault_slots, 0);
|
||||
unsigned int id;
|
||||
|
||||
for_each_set_bit(id, &slots, BITS_PER_LONG) {
|
||||
u8 pipe = id & 0x3;
|
||||
u8 queue = (id >> 2) & 0x7;
|
||||
struct amdgpu_usermode_queue *q;
|
||||
u32 db_ctrl, doorbell;
|
||||
|
||||
amdgpu_gfx_off_ctrl(adev, false);
|
||||
mutex_lock(&adev->srbm_mutex);
|
||||
soc21_grbm_select(adev, 0, pipe, queue, 0);
|
||||
db_ctrl = RREG32_SOC15(GC, 0, regCP_RB_DOORBELL_CONTROL);
|
||||
soc21_grbm_select(adev, 0, 0, 0, 0);
|
||||
mutex_unlock(&adev->srbm_mutex);
|
||||
amdgpu_gfx_off_ctrl(adev, true);
|
||||
|
||||
doorbell = (db_ctrl & CP_RB_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK) >>
|
||||
CP_RB_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
|
||||
q = xa_load(&adev->userq_doorbell_xa, doorbell);
|
||||
if (q)
|
||||
amdgpu_userq_start_hang_detect_work(q);
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_v11_0_handle_priv_fault(struct amdgpu_device *adev,
|
||||
struct amdgpu_iv_entry *entry)
|
||||
{
|
||||
|
||||
@@ -286,6 +286,7 @@ static void gfx_v12_0_ring_invalidate_tlbs(struct amdgpu_ring *ring,
|
||||
bool all_hub, uint8_t dst_sel);
|
||||
static void gfx_v12_0_set_safe_mode(struct amdgpu_device *adev, int xcc_id);
|
||||
static void gfx_v12_0_unset_safe_mode(struct amdgpu_device *adev, int xcc_id);
|
||||
static void gfx_v12_0_userq_priv_fault_work(struct work_struct *work);
|
||||
static void gfx_v12_0_update_perf_clk(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
|
||||
@@ -1609,6 +1610,8 @@ static int gfx_v12_0_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
|
||||
mutex_init(&adev->gfx.mec.reset_mutex);
|
||||
|
||||
INIT_WORK(&adev->gfx.userq_priv_fault_work, gfx_v12_0_userq_priv_fault_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1646,6 +1649,8 @@ static int gfx_v12_0_sw_fini(struct amdgpu_ip_block *ip_block)
|
||||
int i;
|
||||
struct amdgpu_device *adev = ip_block->adev;
|
||||
|
||||
cancel_work_sync(&adev->gfx.userq_priv_fault_work);
|
||||
|
||||
for (i = 0; i < adev->gfx.num_gfx_rings; i++)
|
||||
amdgpu_ring_fini(&adev->gfx.gfx_ring[i]);
|
||||
for (i = 0; i < adev->gfx.num_compute_rings; i++)
|
||||
@@ -1828,6 +1833,12 @@ static void gfx_v12_0_constants_init(struct amdgpu_device *adev)
|
||||
gfx_v12_0_get_cu_info(adev, &adev->gfx.cu_info);
|
||||
gfx_v12_0_get_tcc_info(adev);
|
||||
adev->gfx.config.pa_sc_tile_steering_override = 0;
|
||||
|
||||
/* Set whether texture coordinate truncation is conformant. */
|
||||
tmp = RREG32_SOC15(GC, 0, regTA_CNTL2);
|
||||
adev->gfx.config.ta_cntl2_truncate_coord_mode =
|
||||
REG_GET_FIELD(tmp, TA_CNTL2, TRUNCATE_COORD_MODE);
|
||||
|
||||
/* Program DB_RING_CONTROL for multiple GFX pipes
|
||||
* Default power up value is 1.
|
||||
* Possible values:
|
||||
@@ -5042,6 +5053,40 @@ static int gfx_v12_0_set_priv_inst_fault_state(struct amdgpu_device *adev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A gfx exception IV carries no doorbell. For each faulted slot, read the
|
||||
* doorbell back from the HQD (left in place by the fatal fault), look up the
|
||||
* user queue and kick its per-queue reset.
|
||||
*/
|
||||
static void gfx_v12_0_userq_priv_fault_work(struct work_struct *work)
|
||||
{
|
||||
struct amdgpu_device *adev =
|
||||
container_of(work, struct amdgpu_device, gfx.userq_priv_fault_work);
|
||||
unsigned long slots = xchg(&adev->gfx.userq_priv_fault_slots, 0);
|
||||
unsigned int id;
|
||||
|
||||
for_each_set_bit(id, &slots, BITS_PER_LONG) {
|
||||
u8 pipe = id & 0x3;
|
||||
u8 queue = (id >> 2) & 0x7;
|
||||
struct amdgpu_usermode_queue *q;
|
||||
u32 db_ctrl, doorbell;
|
||||
|
||||
amdgpu_gfx_off_ctrl(adev, false);
|
||||
mutex_lock(&adev->srbm_mutex);
|
||||
soc24_grbm_select(adev, 0, pipe, queue, 0);
|
||||
db_ctrl = RREG32_SOC15(GC, 0, regCP_RB_DOORBELL_CONTROL);
|
||||
soc24_grbm_select(adev, 0, 0, 0, 0);
|
||||
mutex_unlock(&adev->srbm_mutex);
|
||||
amdgpu_gfx_off_ctrl(adev, true);
|
||||
|
||||
doorbell = (db_ctrl & CP_RB_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK) >>
|
||||
CP_RB_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
|
||||
q = xa_load(&adev->userq_doorbell_xa, doorbell);
|
||||
if (q)
|
||||
amdgpu_userq_start_hang_detect_work(q);
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_v12_0_handle_priv_fault(struct amdgpu_device *adev,
|
||||
struct amdgpu_iv_entry *entry)
|
||||
{
|
||||
|
||||
@@ -1597,7 +1597,7 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev)
|
||||
*/
|
||||
static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev)
|
||||
{
|
||||
u32 i, tcc, tcp_addr_config, num_active_tcc = 0;
|
||||
u32 i, tcc, tcp_addr_config, num_active_tcc = 0, num_max_active_tcc;
|
||||
u64 chan_steer, patched_chan_steer = 0;
|
||||
const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches;
|
||||
const u32 dis_tcc_mask =
|
||||
@@ -1611,6 +1611,8 @@ static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev)
|
||||
if (!dis_tcc_mask)
|
||||
return;
|
||||
|
||||
num_max_active_tcc = num_max_tcc - hweight32(dis_tcc_mask);
|
||||
|
||||
/* Each 4-bit nibble contains the index of a TCC used by all TCPs */
|
||||
chan_steer = RREG32(mmTCP_CHAN_STEER_LO) | ((u64)RREG32(mmTCP_CHAN_STEER_HI) << 32ull);
|
||||
|
||||
@@ -1623,9 +1625,12 @@ static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev)
|
||||
patched_chan_steer |= (u64)tcc << (u64)(4 * num_active_tcc);
|
||||
++num_active_tcc;
|
||||
}
|
||||
|
||||
if (num_active_tcc == num_max_active_tcc)
|
||||
break;
|
||||
}
|
||||
|
||||
WARN_ON(num_active_tcc != num_max_tcc - hweight32(dis_tcc_mask));
|
||||
WARN_ON(num_active_tcc != num_max_active_tcc);
|
||||
|
||||
/* Patch number of TCCs used by TCPs */
|
||||
tcp_addr_config = REG_SET_FIELD(RREG32(mmTCP_ADDR_CONFIG),
|
||||
@@ -1635,6 +1640,8 @@ static void gfx_v6_0_setup_tcc(struct amdgpu_device *adev)
|
||||
WREG32(mmTCP_ADDR_CONFIG, tcp_addr_config);
|
||||
WREG32(mmTCP_CHAN_STEER_HI, upper_32_bits(patched_chan_steer));
|
||||
WREG32(mmTCP_CHAN_STEER_LO, lower_32_bits(patched_chan_steer));
|
||||
|
||||
adev->gfx.config.tcc_disabled_mask = dis_tcc_mask;
|
||||
}
|
||||
|
||||
static void gfx_v6_0_config_init(struct amdgpu_device *adev)
|
||||
@@ -1882,11 +1889,13 @@ static int gfx_v6_0_ring_test_ring(struct amdgpu_ring *ring)
|
||||
return r;
|
||||
}
|
||||
|
||||
static void gfx_v6_0_ring_emit_vgt_flush(struct amdgpu_ring *ring)
|
||||
static void gfx_v6_0_ring_emit_event_write(struct amdgpu_ring *ring,
|
||||
uint32_t event_type,
|
||||
uint32_t event_index)
|
||||
{
|
||||
amdgpu_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE, 0));
|
||||
amdgpu_ring_write(ring, EVENT_TYPE(VGT_FLUSH) |
|
||||
EVENT_INDEX(0));
|
||||
amdgpu_ring_write(ring, EVENT_TYPE(event_type) |
|
||||
EVENT_INDEX(event_index));
|
||||
}
|
||||
|
||||
static void gfx_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
|
||||
@@ -1925,12 +1934,6 @@ static void gfx_v6_0_ring_emit_ib(struct amdgpu_ring *ring,
|
||||
unsigned vmid = AMDGPU_JOB_GET_VMID(job);
|
||||
u32 header, control = 0;
|
||||
|
||||
/* insert SWITCH_BUFFER packet before first IB in the ring frame */
|
||||
if (flags & AMDGPU_HAVE_CTX_SWITCH) {
|
||||
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
|
||||
amdgpu_ring_write(ring, 0);
|
||||
}
|
||||
|
||||
if (ib->flags & AMDGPU_IB_FLAG_CE)
|
||||
header = PACKET3(PACKET3_INDIRECT_BUFFER_CONST, 2);
|
||||
else
|
||||
@@ -2133,12 +2136,24 @@ static int gfx_v6_0_cp_gfx_start(struct amdgpu_device *adev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfx_v6_0_cp_gfx_resume() - Initialize CP rings
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* In GFX6 GPUs, compute takes the same CP path as graphics.
|
||||
* CP ME command parser executes packets for each ring buffer:
|
||||
* RB0 supports graphics, RB1 and RB2 are compute only.
|
||||
* Initialize all three rings before calling gfx_v6_0_cp_gfx_start()
|
||||
* to make sure they are all in a sane state before execution starts.
|
||||
*/
|
||||
static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ring *ring;
|
||||
u32 tmp;
|
||||
u32 rb_bufsz;
|
||||
int r;
|
||||
int i;
|
||||
u64 rptr_addr;
|
||||
|
||||
WREG32(mmCP_SEM_WAIT_TIMER, 0x0);
|
||||
@@ -2151,8 +2166,12 @@ static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
|
||||
WREG32(mmSCRATCH_ADDR, 0);
|
||||
|
||||
/* ring 0 - compute and gfx */
|
||||
/* Set ring buffer size */
|
||||
ring = &adev->gfx.gfx_ring[0];
|
||||
*ring->wptr_cpu_addr = 0;
|
||||
*ring->rptr_cpu_addr = 0;
|
||||
amdgpu_ring_clear_ring(ring);
|
||||
|
||||
/* Set ring buffer size */
|
||||
rb_bufsz = order_base_2(ring->ring_size / 8);
|
||||
tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
|
||||
|
||||
@@ -2164,7 +2183,8 @@ static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
|
||||
/* Initialize the ring buffer's read and write pointers */
|
||||
WREG32(mmCP_RB0_CNTL, tmp | CP_RB0_CNTL__RB_RPTR_WR_ENA_MASK);
|
||||
ring->wptr = 0;
|
||||
WREG32(mmCP_RB0_WPTR, ring->wptr);
|
||||
WREG32(mmCP_RB0_WPTR, lower_32_bits(ring->wptr));
|
||||
WREG32(mmCP_RB0_RPTR, lower_32_bits(ring->wptr));
|
||||
|
||||
/* set the wb address whether it's enabled or not */
|
||||
rptr_addr = ring->rptr_gpu_addr;
|
||||
@@ -2178,12 +2198,86 @@ static int gfx_v6_0_cp_gfx_resume(struct amdgpu_device *adev)
|
||||
|
||||
WREG32(mmCP_RB0_BASE, ring->gpu_addr >> 8);
|
||||
|
||||
/* ring 1 - compute only */
|
||||
if (adev->gfx.num_compute_rings >= 1) {
|
||||
ring = &adev->gfx.compute_ring[0];
|
||||
*ring->wptr_cpu_addr = 0;
|
||||
*ring->rptr_cpu_addr = 0;
|
||||
amdgpu_ring_clear_ring(ring);
|
||||
|
||||
rb_bufsz = order_base_2(ring->ring_size / 8);
|
||||
tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE / 8) << 8) | rb_bufsz;
|
||||
#ifdef __BIG_ENDIAN
|
||||
tmp |= BUF_SWAP_32BIT;
|
||||
#endif
|
||||
WREG32(mmCP_RB1_CNTL, tmp);
|
||||
|
||||
WREG32(mmCP_RB1_CNTL, tmp | CP_RB1_CNTL__RB_RPTR_WR_ENA_MASK);
|
||||
ring->wptr = 0;
|
||||
WREG32(mmCP_RB1_WPTR, lower_32_bits(ring->wptr));
|
||||
WREG32(mmCP_RB1_RPTR, lower_32_bits(ring->wptr));
|
||||
|
||||
rptr_addr = ring->rptr_gpu_addr;
|
||||
WREG32(mmCP_RB1_RPTR_ADDR, lower_32_bits(rptr_addr));
|
||||
WREG32(mmCP_RB1_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & 0xFF);
|
||||
|
||||
mdelay(1);
|
||||
WREG32(mmCP_RB1_CNTL, tmp);
|
||||
WREG32(mmCP_RB1_BASE, ring->gpu_addr >> 8);
|
||||
}
|
||||
|
||||
/* ring 2 - compute only */
|
||||
if (adev->gfx.num_compute_rings >= 2) {
|
||||
ring = &adev->gfx.compute_ring[1];
|
||||
*ring->wptr_cpu_addr = 0;
|
||||
*ring->rptr_cpu_addr = 0;
|
||||
amdgpu_ring_clear_ring(ring);
|
||||
|
||||
rb_bufsz = order_base_2(ring->ring_size / 8);
|
||||
tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE / 8) << 8) | rb_bufsz;
|
||||
#ifdef __BIG_ENDIAN
|
||||
tmp |= BUF_SWAP_32BIT;
|
||||
#endif
|
||||
WREG32(mmCP_RB2_CNTL, tmp);
|
||||
|
||||
WREG32(mmCP_RB2_CNTL, tmp | CP_RB2_CNTL__RB_RPTR_WR_ENA_MASK);
|
||||
ring->wptr = 0;
|
||||
WREG32(mmCP_RB2_WPTR, lower_32_bits(ring->wptr));
|
||||
WREG32(mmCP_RB2_RPTR, lower_32_bits(ring->wptr));
|
||||
|
||||
rptr_addr = ring->rptr_gpu_addr;
|
||||
WREG32(mmCP_RB2_RPTR_ADDR, lower_32_bits(rptr_addr));
|
||||
WREG32(mmCP_RB2_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & 0xFF);
|
||||
|
||||
mdelay(1);
|
||||
WREG32(mmCP_RB2_CNTL, tmp);
|
||||
WREG32(mmCP_RB2_BASE, ring->gpu_addr >> 8);
|
||||
}
|
||||
|
||||
/* start the rings */
|
||||
gfx_v6_0_cp_gfx_start(adev);
|
||||
r = amdgpu_ring_test_helper(ring);
|
||||
|
||||
/* Wait for the initial packets to finish, run gfx ring test */
|
||||
r = amdgpu_ring_test_helper(&adev->gfx.gfx_ring[0]);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
for (i = 0; i < adev->gfx.num_compute_rings; i++) {
|
||||
ring = &adev->gfx.compute_ring[i];
|
||||
|
||||
r = amdgpu_ring_alloc(ring, 2);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
amdgpu_ring_write(ring, PACKET3_COMPUTE(PACKET3_CLEAR_STATE, 0));
|
||||
amdgpu_ring_write(ring, 0);
|
||||
amdgpu_ring_commit(ring);
|
||||
|
||||
r = amdgpu_ring_test_helper(ring);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2228,66 +2322,6 @@ static void gfx_v6_0_ring_set_wptr_compute(struct amdgpu_ring *ring)
|
||||
|
||||
}
|
||||
|
||||
static int gfx_v6_0_cp_compute_resume(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ring *ring;
|
||||
u32 tmp;
|
||||
u32 rb_bufsz;
|
||||
int i, r;
|
||||
u64 rptr_addr;
|
||||
|
||||
/* ring1 - compute only */
|
||||
/* Set ring buffer size */
|
||||
|
||||
ring = &adev->gfx.compute_ring[0];
|
||||
rb_bufsz = order_base_2(ring->ring_size / 8);
|
||||
tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
|
||||
#ifdef __BIG_ENDIAN
|
||||
tmp |= BUF_SWAP_32BIT;
|
||||
#endif
|
||||
WREG32(mmCP_RB1_CNTL, tmp);
|
||||
|
||||
WREG32(mmCP_RB1_CNTL, tmp | CP_RB1_CNTL__RB_RPTR_WR_ENA_MASK);
|
||||
ring->wptr = 0;
|
||||
WREG32(mmCP_RB1_WPTR, ring->wptr);
|
||||
|
||||
rptr_addr = ring->rptr_gpu_addr;
|
||||
WREG32(mmCP_RB1_RPTR_ADDR, lower_32_bits(rptr_addr));
|
||||
WREG32(mmCP_RB1_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & 0xFF);
|
||||
|
||||
mdelay(1);
|
||||
WREG32(mmCP_RB1_CNTL, tmp);
|
||||
WREG32(mmCP_RB1_BASE, ring->gpu_addr >> 8);
|
||||
|
||||
ring = &adev->gfx.compute_ring[1];
|
||||
rb_bufsz = order_base_2(ring->ring_size / 8);
|
||||
tmp = (order_base_2(AMDGPU_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
|
||||
#ifdef __BIG_ENDIAN
|
||||
tmp |= BUF_SWAP_32BIT;
|
||||
#endif
|
||||
WREG32(mmCP_RB2_CNTL, tmp);
|
||||
|
||||
WREG32(mmCP_RB2_CNTL, tmp | CP_RB2_CNTL__RB_RPTR_WR_ENA_MASK);
|
||||
ring->wptr = 0;
|
||||
WREG32(mmCP_RB2_WPTR, ring->wptr);
|
||||
rptr_addr = ring->rptr_gpu_addr;
|
||||
WREG32(mmCP_RB2_RPTR_ADDR, lower_32_bits(rptr_addr));
|
||||
WREG32(mmCP_RB2_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & 0xFF);
|
||||
|
||||
mdelay(1);
|
||||
WREG32(mmCP_RB2_CNTL, tmp);
|
||||
WREG32(mmCP_RB2_BASE, ring->gpu_addr >> 8);
|
||||
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
r = amdgpu_ring_test_helper(&adev->gfx.compute_ring[i]);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gfx_v6_0_cp_enable(struct amdgpu_device *adev, bool enable)
|
||||
{
|
||||
gfx_v6_0_cp_gfx_enable(adev, enable);
|
||||
@@ -2337,9 +2371,6 @@ static int gfx_v6_0_cp_resume(struct amdgpu_device *adev)
|
||||
return r;
|
||||
|
||||
r = gfx_v6_0_cp_gfx_resume(adev);
|
||||
if (r)
|
||||
return r;
|
||||
r = gfx_v6_0_cp_compute_resume(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
@@ -2350,7 +2381,7 @@ static int gfx_v6_0_cp_resume(struct amdgpu_device *adev)
|
||||
|
||||
static void gfx_v6_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
|
||||
{
|
||||
int usepfp = (ring->funcs->type == AMDGPU_RING_TYPE_GFX);
|
||||
int usepfp = 1;
|
||||
uint32_t seq = ring->fence_drv.sync_seq;
|
||||
uint64_t addr = ring->fence_drv.gpu_addr;
|
||||
|
||||
@@ -2363,20 +2394,12 @@ static void gfx_v6_0_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
|
||||
amdgpu_ring_write(ring, seq);
|
||||
amdgpu_ring_write(ring, 0xffffffff);
|
||||
amdgpu_ring_write(ring, 4); /* poll interval */
|
||||
|
||||
if (usepfp) {
|
||||
/* synce CE with ME to prevent CE fetch CEIB before context switch done */
|
||||
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
|
||||
amdgpu_ring_write(ring, 0);
|
||||
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
|
||||
amdgpu_ring_write(ring, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
|
||||
unsigned vmid, uint64_t pd_addr)
|
||||
{
|
||||
int usepfp = (ring->funcs->type == AMDGPU_RING_TYPE_GFX);
|
||||
int usepfp = 1;
|
||||
|
||||
amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr);
|
||||
|
||||
@@ -2394,19 +2417,31 @@ static void gfx_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
|
||||
/* sync PFP to ME, otherwise we might get invalid PFP reads */
|
||||
amdgpu_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
|
||||
amdgpu_ring_write(ring, 0x0);
|
||||
|
||||
/* synce CE with ME to prevent CE fetch CEIB before context switch done */
|
||||
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
|
||||
amdgpu_ring_write(ring, 0);
|
||||
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
|
||||
amdgpu_ring_write(ring, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int gfx_v6_0_ring_emit_init_cond_exec(struct amdgpu_ring *ring,
|
||||
uint64_t gpu_addr)
|
||||
{
|
||||
unsigned int ret;
|
||||
|
||||
/*
|
||||
* Discard following DWs after this packet when gpu_addr==0
|
||||
* The packet is only 4 DW on GFX6 (as opposed to GFX7+).
|
||||
*/
|
||||
amdgpu_ring_write(ring, PACKET3(PACKET3_COND_EXEC, 2));
|
||||
amdgpu_ring_write(ring, lower_32_bits(gpu_addr));
|
||||
amdgpu_ring_write(ring, upper_32_bits(gpu_addr));
|
||||
ret = ring->wptr & ring->buf_mask;
|
||||
/* patch dummy value later */
|
||||
amdgpu_ring_write(ring, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void gfx_v6_0_ring_emit_wreg(struct amdgpu_ring *ring,
|
||||
uint32_t reg, uint32_t val)
|
||||
{
|
||||
int usepfp = (ring->funcs->type == AMDGPU_RING_TYPE_GFX);
|
||||
int usepfp = 1;
|
||||
|
||||
amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
|
||||
amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) |
|
||||
@@ -2995,12 +3030,30 @@ static uint64_t gfx_v6_0_get_gpu_clock_counter(struct amdgpu_device *adev)
|
||||
return clock;
|
||||
}
|
||||
|
||||
static void gfx_v6_0_ring_emit_sb(struct amdgpu_ring *ring)
|
||||
{
|
||||
amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
|
||||
amdgpu_ring_write(ring, 0);
|
||||
}
|
||||
|
||||
static void gfx_v6_ring_emit_cntxcntl(struct amdgpu_ring *ring, uint32_t flags)
|
||||
{
|
||||
if (flags & AMDGPU_HAVE_CTX_SWITCH)
|
||||
gfx_v6_0_ring_emit_vgt_flush(ring);
|
||||
u32 dw2 = 0x80000000; /* set load_enable otherwise this package is just NOPs */
|
||||
|
||||
if (flags & AMDGPU_HAVE_CTX_SWITCH) {
|
||||
gfx_v6_0_ring_emit_event_write(ring, VS_PARTIAL_FLUSH, 4);
|
||||
gfx_v6_0_ring_emit_event_write(ring, VGT_FLUSH, 0);
|
||||
|
||||
/* set load_global_config (load_global_uconfig doesn't exist on GFX6) */
|
||||
dw2 |= 0x1;
|
||||
/* set load_cs_sh_regs */
|
||||
dw2 |= 0x01000000;
|
||||
/* set load_per_context_state & load_gfx_sh_regs */
|
||||
dw2 |= 0x10002;
|
||||
}
|
||||
|
||||
amdgpu_ring_write(ring, PACKET3(PACKET3_CONTEXT_CONTROL, 1));
|
||||
amdgpu_ring_write(ring, 0x80000000);
|
||||
amdgpu_ring_write(ring, dw2);
|
||||
amdgpu_ring_write(ring, 0);
|
||||
}
|
||||
|
||||
@@ -3102,6 +3155,11 @@ static int gfx_v6_0_early_init(struct amdgpu_ip_block *ip_block)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gfx_v6_0_late_init(struct amdgpu_ip_block *ip_block)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gfx_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
{
|
||||
struct amdgpu_ring *ring;
|
||||
@@ -3172,6 +3230,11 @@ static int gfx_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
|
||||
adev->gfx.compute_supported_reset =
|
||||
amdgpu_get_soft_full_reset_mask(&adev->gfx.compute_ring[0]);
|
||||
|
||||
if (!amdgpu_sriov_vf(adev) && !adev->debug_disable_ip_block_soft_reset) {
|
||||
adev->gfx.compute_supported_reset |= AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET;
|
||||
adev->gfx.gfx_supported_reset |= AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -3254,6 +3317,99 @@ static int gfx_v6_0_wait_for_idle(struct amdgpu_ip_block *ip_block)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int gfx_v6_0_soft_reset(struct amdgpu_ip_block *ip_block)
|
||||
{
|
||||
struct amdgpu_device *adev = ip_block->adev;
|
||||
u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
|
||||
u32 tmp;
|
||||
int r;
|
||||
|
||||
grbm_soft_reset =
|
||||
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CP, 1) |
|
||||
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CB, 1) |
|
||||
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_RLC, 1) |
|
||||
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_DB, 1) |
|
||||
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_GDS, 1) |
|
||||
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_PA, 1) |
|
||||
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_SC, 1) |
|
||||
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_BCI, 1) |
|
||||
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_SPI, 1) |
|
||||
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_SX, 1) |
|
||||
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_TC, 1) |
|
||||
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_TA, 1) |
|
||||
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_VGT, 1) |
|
||||
REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_IA, 1);
|
||||
|
||||
srbm_soft_reset =
|
||||
REG_SET_FIELD(0, SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1) |
|
||||
REG_SET_FIELD(0, SRBM_SOFT_RESET, SOFT_RESET_SEM, 1);
|
||||
|
||||
ip_block->version->funcs->set_clockgating_state(ip_block, AMD_CG_STATE_UNGATE);
|
||||
ip_block->version->funcs->set_powergating_state(ip_block, AMD_PG_STATE_UNGATE);
|
||||
ip_block->version->funcs->suspend(ip_block);
|
||||
|
||||
if (grbm_soft_reset || srbm_soft_reset) {
|
||||
tmp = RREG32(mmGMCON_DEBUG);
|
||||
tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_STALL, 1);
|
||||
tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_CLEAR, 1);
|
||||
WREG32(mmGMCON_DEBUG, tmp);
|
||||
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
if (grbm_soft_reset) {
|
||||
tmp = RREG32(mmGRBM_SOFT_RESET);
|
||||
tmp |= grbm_soft_reset;
|
||||
dev_info(adev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp);
|
||||
WREG32(mmGRBM_SOFT_RESET, tmp);
|
||||
tmp = RREG32(mmGRBM_SOFT_RESET);
|
||||
|
||||
udelay(100);
|
||||
|
||||
tmp &= ~grbm_soft_reset;
|
||||
WREG32(mmGRBM_SOFT_RESET, tmp);
|
||||
tmp = RREG32(mmGRBM_SOFT_RESET);
|
||||
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
if (srbm_soft_reset) {
|
||||
tmp = RREG32(mmSRBM_SOFT_RESET);
|
||||
tmp |= srbm_soft_reset;
|
||||
dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
|
||||
WREG32(mmSRBM_SOFT_RESET, tmp);
|
||||
tmp = RREG32(mmSRBM_SOFT_RESET);
|
||||
|
||||
udelay(100);
|
||||
|
||||
tmp &= ~srbm_soft_reset;
|
||||
WREG32(mmSRBM_SOFT_RESET, tmp);
|
||||
tmp = RREG32(mmSRBM_SOFT_RESET);
|
||||
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
if (grbm_soft_reset || srbm_soft_reset) {
|
||||
tmp = RREG32(mmGMCON_DEBUG);
|
||||
tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_STALL, 0);
|
||||
tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_CLEAR, 0);
|
||||
WREG32(mmGMCON_DEBUG, tmp);
|
||||
}
|
||||
|
||||
/* Wait a little for things to settle down */
|
||||
udelay(100);
|
||||
|
||||
r = ip_block->version->funcs->resume(ip_block);
|
||||
r |= ip_block->version->funcs->late_init(ip_block);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
ip_block->version->funcs->set_clockgating_state(ip_block, AMD_CG_STATE_GATE);
|
||||
ip_block->version->funcs->set_powergating_state(ip_block, AMD_PG_STATE_GATE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gfx_v6_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev,
|
||||
enum amdgpu_interrupt_state state)
|
||||
{
|
||||
@@ -3502,6 +3658,7 @@ static void gfx_v6_0_emit_mem_sync(struct amdgpu_ring *ring)
|
||||
static const struct amd_ip_funcs gfx_v6_0_ip_funcs = {
|
||||
.name = "gfx_v6_0",
|
||||
.early_init = gfx_v6_0_early_init,
|
||||
.late_init = gfx_v6_0_late_init,
|
||||
.sw_init = gfx_v6_0_sw_init,
|
||||
.sw_fini = gfx_v6_0_sw_fini,
|
||||
.hw_init = gfx_v6_0_hw_init,
|
||||
@@ -3510,6 +3667,7 @@ static const struct amd_ip_funcs gfx_v6_0_ip_funcs = {
|
||||
.resume = gfx_v6_0_resume,
|
||||
.is_idle = gfx_v6_0_is_idle,
|
||||
.wait_for_idle = gfx_v6_0_wait_for_idle,
|
||||
.soft_reset = gfx_v6_0_soft_reset,
|
||||
.set_clockgating_state = gfx_v6_0_set_clockgating_state,
|
||||
.set_powergating_state = gfx_v6_0_set_powergating_state,
|
||||
};
|
||||
@@ -3523,13 +3681,16 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = {
|
||||
.get_wptr = gfx_v6_0_ring_get_wptr,
|
||||
.set_wptr = gfx_v6_0_ring_set_wptr_gfx,
|
||||
.emit_frame_size =
|
||||
4 + /* gfx_v6_0_ring_emit_init_cond_exec (from amdgpu_ib_schedule) */
|
||||
4 + /* gfx_v6_0_ring_emit_init_cond_exec (from amdgpu_vm_flush) */
|
||||
5 + 5 + /* hdp flush / invalidate */
|
||||
14 + 14 + 14 + /* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */
|
||||
7 + 4 + /* gfx_v6_0_ring_emit_pipeline_sync */
|
||||
SI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + 6 + /* gfx_v6_0_ring_emit_vm_flush */
|
||||
3 + 2 + /* gfx_v6_ring_emit_cntxcntl including vgt flush */
|
||||
7 + /* gfx_v6_0_ring_emit_pipeline_sync */
|
||||
SI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + 2 + /* gfx_v6_0_ring_emit_vm_flush */
|
||||
3 * 2 + /* gfx_v6_0_ring_emit_sb x3 (from amdgpu_vm_flush, amdgpu_ib_schedule) */
|
||||
3 + 2 + 2 + /* gfx_v6_ring_emit_cntxcntl including VGT flush */
|
||||
5, /* SURFACE_SYNC */
|
||||
.emit_ib_size = 6, /* gfx_v6_0_ring_emit_ib */
|
||||
.emit_ib_size = 4, /* gfx_v6_0_ring_emit_ib */
|
||||
.emit_ib = gfx_v6_0_ring_emit_ib,
|
||||
.emit_fence = gfx_v6_0_ring_emit_fence,
|
||||
.emit_pipeline_sync = gfx_v6_0_ring_emit_pipeline_sync,
|
||||
@@ -3537,7 +3698,9 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = {
|
||||
.test_ring = gfx_v6_0_ring_test_ring,
|
||||
.test_ib = gfx_v6_0_ring_test_ib,
|
||||
.insert_nop = amdgpu_ring_insert_nop,
|
||||
.emit_switch_buffer = gfx_v6_0_ring_emit_sb,
|
||||
.emit_cntxcntl = gfx_v6_ring_emit_cntxcntl,
|
||||
.init_cond_exec = gfx_v6_0_ring_emit_init_cond_exec,
|
||||
.emit_wreg = gfx_v6_0_ring_emit_wreg,
|
||||
.emit_mem_sync = gfx_v6_0_emit_mem_sync,
|
||||
};
|
||||
@@ -3550,12 +3713,15 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = {
|
||||
.get_wptr = gfx_v6_0_ring_get_wptr,
|
||||
.set_wptr = gfx_v6_0_ring_set_wptr_compute,
|
||||
.emit_frame_size =
|
||||
4 + /* gfx_v6_0_ring_emit_init_cond_exec (from amdgpu_ib_schedule) */
|
||||
4 + /* gfx_v6_0_ring_emit_init_cond_exec (from amdgpu_vm_flush) */
|
||||
5 + 5 + /* hdp flush / invalidate */
|
||||
7 + /* gfx_v6_0_ring_emit_pipeline_sync */
|
||||
SI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + /* gfx_v6_0_ring_emit_vm_flush */
|
||||
SI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + 2 + /* gfx_v6_0_ring_emit_vm_flush */
|
||||
14 + 14 + 14 + /* gfx_v6_0_ring_emit_fence x3 for user fence, vm fence */
|
||||
3 * 2 + /* gfx_v6_0_ring_emit_sb x3 (from amdgpu_vm_flush, amdgpu_ib_schedule) */
|
||||
5, /* SURFACE_SYNC */
|
||||
.emit_ib_size = 6, /* gfx_v6_0_ring_emit_ib */
|
||||
.emit_ib_size = 4, /* gfx_v6_0_ring_emit_ib */
|
||||
.emit_ib = gfx_v6_0_ring_emit_ib,
|
||||
.emit_fence = gfx_v6_0_ring_emit_fence,
|
||||
.emit_pipeline_sync = gfx_v6_0_ring_emit_pipeline_sync,
|
||||
@@ -3563,6 +3729,8 @@ static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_compute = {
|
||||
.test_ring = gfx_v6_0_ring_test_ring,
|
||||
.test_ib = gfx_v6_0_ring_test_ib,
|
||||
.insert_nop = amdgpu_ring_insert_nop,
|
||||
.emit_switch_buffer = gfx_v6_0_ring_emit_sb,
|
||||
.init_cond_exec = gfx_v6_0_ring_emit_init_cond_exec,
|
||||
.emit_wreg = gfx_v6_0_ring_emit_wreg,
|
||||
.emit_mem_sync = gfx_v6_0_emit_mem_sync,
|
||||
};
|
||||
|
||||
@@ -640,10 +640,6 @@ static int gmc_v10_0_late_init(struct amdgpu_ip_block *ip_block)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_gmc_ras_late_init(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return amdgpu_irq_get(adev, &adev->gmc.vm_fault, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -646,10 +646,6 @@ static int gmc_v11_0_late_init(struct amdgpu_ip_block *ip_block)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_gmc_ras_late_init(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return amdgpu_irq_get(adev, &adev->gmc.vm_fault, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -682,10 +682,6 @@ static int gmc_v12_0_late_init(struct amdgpu_ip_block *ip_block)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_gmc_ras_late_init(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return amdgpu_irq_get(adev, &adev->gmc.vm_fault, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -267,9 +267,24 @@ static bool gmc_v12_1_get_vmid_pasid_mapping_info(struct amdgpu_device *adev,
|
||||
* by the amdgpu vm/hsa code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* gmc_v12_1_use_invalidate_semaphore - judge whether to use semaphore
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @vmhub: vmhub type
|
||||
*
|
||||
*/
|
||||
static bool gmc_v12_1_use_invalidate_semaphore(struct amdgpu_device *adev,
|
||||
uint32_t vmhub)
|
||||
{
|
||||
return ((!AMDGPU_IS_GFXHUB(vmhub)) &&
|
||||
(!amdgpu_sriov_vf(adev)));
|
||||
}
|
||||
|
||||
static void gmc_v12_1_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid,
|
||||
unsigned int vmhub, uint32_t flush_type)
|
||||
{
|
||||
bool use_semaphore = gmc_v12_1_use_invalidate_semaphore(adev, vmhub);
|
||||
struct amdgpu_vmhub *hub = &adev->vmhub[vmhub];
|
||||
u32 inv_req = hub->vmhub_funcs->get_invalidate_req(vmid, flush_type);
|
||||
u32 tmp;
|
||||
@@ -283,6 +298,19 @@ static void gmc_v12_1_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid,
|
||||
|
||||
spin_lock(&adev->gmc.invalidate_lock);
|
||||
|
||||
if (use_semaphore) {
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
/* a read return value of 1 means semaphore acuqire */
|
||||
tmp = RREG32_RLC_NO_KIQ(hub->vm_inv_eng0_sem + hub->eng_distance * eng, hub_ip);
|
||||
if (tmp & 0x1)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (i >= adev->usec_timeout)
|
||||
DRM_ERROR("Timeout waiting for sem acquire in VM flush!\n");
|
||||
}
|
||||
|
||||
WREG32_RLC_NO_KIQ(hub->vm_inv_eng0_req + hub->eng_distance * eng, inv_req, hub_ip);
|
||||
|
||||
/* Wait for ACK with a delay.*/
|
||||
@@ -296,6 +324,9 @@ static void gmc_v12_1_flush_vm_hub(struct amdgpu_device *adev, uint32_t vmid,
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (use_semaphore)
|
||||
WREG32_RLC_NO_KIQ(hub->vm_inv_eng0_sem + hub->eng_distance * eng, 0, hub_ip);
|
||||
|
||||
/* Issue additional private vm invalidation to MMHUB */
|
||||
if (!AMDGPU_IS_GFXHUB(vmhub) &&
|
||||
(hub->vm_l2_bank_select_reserved_cid2) &&
|
||||
@@ -396,7 +427,7 @@ static void gmc_v12_1_flush_gpu_tlb_pasid(struct amdgpu_device *adev,
|
||||
|
||||
if (all_hub) {
|
||||
/* invalidate mm_hub */
|
||||
if (test_bit(AMDGPU_MMHUB1(0), adev->vmhubs_mask)) {
|
||||
if (test_bit(AMDGPU_MMHUB0(0), adev->vmhubs_mask)) {
|
||||
input.hub_id = AMDGPU_MMHUB0(0);
|
||||
adev->mes.funcs->invalidate_tlbs_pasid(&adev->mes, &input);
|
||||
}
|
||||
@@ -431,10 +462,17 @@ static void gmc_v12_1_flush_gpu_tlb_pasid(struct amdgpu_device *adev,
|
||||
static uint64_t gmc_v12_1_emit_flush_gpu_tlb(struct amdgpu_ring *ring,
|
||||
unsigned vmid, uint64_t pd_addr)
|
||||
{
|
||||
bool use_semaphore = gmc_v12_1_use_invalidate_semaphore(ring->adev, ring->vm_hub);
|
||||
struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub];
|
||||
uint32_t req = hub->vmhub_funcs->get_invalidate_req(vmid, 0);
|
||||
unsigned eng = ring->vm_inv_eng;
|
||||
|
||||
if (use_semaphore)
|
||||
/* a read return value of 1 means semaphore acuqire */
|
||||
amdgpu_ring_emit_reg_wait(ring,
|
||||
hub->vm_inv_eng0_sem +
|
||||
hub->eng_distance * eng, 0x1, 0x1);
|
||||
|
||||
amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_lo32 +
|
||||
(hub->ctx_addr_distance * vmid),
|
||||
lower_32_bits(pd_addr));
|
||||
@@ -449,6 +487,14 @@ static uint64_t gmc_v12_1_emit_flush_gpu_tlb(struct amdgpu_ring *ring,
|
||||
hub->eng_distance * eng,
|
||||
req, 1 << vmid);
|
||||
|
||||
if (use_semaphore)
|
||||
/*
|
||||
* add semaphore release after invalidation,
|
||||
* write with 0 means semaphore release
|
||||
*/
|
||||
amdgpu_ring_emit_wreg(ring, hub->vm_inv_eng0_sem +
|
||||
hub->eng_distance * eng, 0);
|
||||
|
||||
return pd_addr;
|
||||
}
|
||||
|
||||
|
||||
@@ -1640,10 +1640,6 @@ static int gmc_v9_0_late_init(struct amdgpu_ip_block *ip_block)
|
||||
amdgpu_ras_reset_error_count(adev, AMDGPU_RAS_BLOCK__HDP);
|
||||
}
|
||||
|
||||
r = amdgpu_gmc_ras_late_init(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return amdgpu_irq_get(adev, &adev->gmc.vm_fault, 0);
|
||||
}
|
||||
|
||||
@@ -2063,7 +2059,6 @@ static int gmc_v9_0_sw_fini(struct amdgpu_ip_block *ip_block)
|
||||
if (amdgpu_is_multi_aid(adev))
|
||||
amdgpu_gmc_sysfs_fini(adev);
|
||||
|
||||
amdgpu_gmc_ras_fini(adev);
|
||||
amdgpu_gem_force_release(adev);
|
||||
amdgpu_vm_manager_fini(adev);
|
||||
if (!adev->gmc.real_vram_size) {
|
||||
|
||||
@@ -772,15 +772,28 @@ static int jpeg_v4_0_5_ring_reset(struct amdgpu_ring *ring,
|
||||
unsigned int vmid,
|
||||
struct amdgpu_fence *timedout_fence)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
u32 pg_flags = adev->pg_flags;
|
||||
int r;
|
||||
|
||||
amdgpu_ring_reset_helper_begin(ring, timedout_fence);
|
||||
r = jpeg_v4_0_5_stop(ring->adev);
|
||||
if (r)
|
||||
return r;
|
||||
r = jpeg_v4_0_5_start(ring->adev);
|
||||
|
||||
/*
|
||||
* The DPG stop path only clears the JPEG_PG_MODE bit and never resets a
|
||||
* hung JRBC, so the post-reset ring test times out and the driver falls
|
||||
* back to a full MODE1 reset. Temporarily force the static power-gating
|
||||
* path so the stop/start sequence actually power-cycles the JPEG block
|
||||
* (JMI soft reset + static power off/on), matching the working jpeg_v4_0
|
||||
* reset.
|
||||
*/
|
||||
adev->pg_flags &= ~AMD_PG_SUPPORT_JPEG_DPG;
|
||||
r = jpeg_v4_0_5_stop(adev);
|
||||
if (!r)
|
||||
r = jpeg_v4_0_5_start(adev);
|
||||
adev->pg_flags = pg_flags;
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
|
||||
}
|
||||
|
||||
|
||||
@@ -648,15 +648,28 @@ static int jpeg_v5_0_0_ring_reset(struct amdgpu_ring *ring,
|
||||
unsigned int vmid,
|
||||
struct amdgpu_fence *timedout_fence)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
u32 pg_flags = adev->pg_flags;
|
||||
int r;
|
||||
|
||||
amdgpu_ring_reset_helper_begin(ring, timedout_fence);
|
||||
r = jpeg_v5_0_0_stop(ring->adev);
|
||||
if (r)
|
||||
return r;
|
||||
r = jpeg_v5_0_0_start(ring->adev);
|
||||
|
||||
/*
|
||||
* The DPG stop path only clears the JPEG_PG_MODE bit and never resets a
|
||||
* hung JRBC, so the post-reset ring test times out and the driver falls
|
||||
* back to a full MODE1 reset. Temporarily force the static power-gating
|
||||
* path so the stop/start sequence actually power-cycles the JPEG block
|
||||
* (JMI soft reset + ONO1 power off/on), matching the working jpeg_v4_0
|
||||
* reset.
|
||||
*/
|
||||
adev->pg_flags &= ~AMD_PG_SUPPORT_JPEG_DPG;
|
||||
r = jpeg_v5_0_0_stop(adev);
|
||||
if (!r)
|
||||
r = jpeg_v5_0_0_start(adev);
|
||||
adev->pg_flags = pg_flags;
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
|
||||
}
|
||||
|
||||
|
||||
@@ -637,15 +637,28 @@ static int jpeg_v5_3_0_ring_reset(struct amdgpu_ring *ring,
|
||||
unsigned int vmid,
|
||||
struct amdgpu_fence *timedout_fence)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
u32 pg_flags = adev->pg_flags;
|
||||
int r;
|
||||
|
||||
amdgpu_ring_reset_helper_begin(ring, timedout_fence);
|
||||
r = jpeg_v5_3_0_stop(ring->adev);
|
||||
if (r)
|
||||
return r;
|
||||
r = jpeg_v5_3_0_start(ring->adev);
|
||||
|
||||
/*
|
||||
* The DPG stop path only clears the JPEG_PG_MODE bit and never resets a
|
||||
* hung JRBC, so the post-reset ring test times out and the driver falls
|
||||
* back to a full MODE1 reset. Temporarily force the static power-gating
|
||||
* path so the stop/start sequence actually power-cycles the JPEG block
|
||||
* (JMI soft reset + static power off/on), matching the working jpeg_v4_0
|
||||
* reset.
|
||||
*/
|
||||
adev->pg_flags &= ~AMD_PG_SUPPORT_JPEG_DPG;
|
||||
r = jpeg_v5_3_0_stop(adev);
|
||||
if (!r)
|
||||
r = jpeg_v5_3_0_start(adev);
|
||||
adev->pg_flags = pg_flags;
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "amdgpu_gfx.h"
|
||||
#include "mes_userqueue.h"
|
||||
#include "amdgpu_userq_fence.h"
|
||||
#include "amdgpu_trace.h"
|
||||
|
||||
#define AMDGPU_USERQ_PROC_CTX_SZ PAGE_SIZE
|
||||
#define AMDGPU_USERQ_GANG_CTX_SZ PAGE_SIZE
|
||||
@@ -143,10 +144,23 @@ static int mes_userq_map(struct amdgpu_usermode_queue *queue)
|
||||
queue_input.doorbell_offset = userq_props->doorbell_index;
|
||||
queue_input.page_table_base_addr = amdgpu_gmc_pd_addr(queue->vm->root.bo);
|
||||
queue_input.wptr_mc_addr = queue->wptr_obj.gpu_addr;
|
||||
|
||||
if (mes->use_rs64mem) {
|
||||
amdgpu_mes_alloc_proc_ctx_index(mes, queue);
|
||||
queue_input.process_context_array_index = queue->proc_ctx_array_index;
|
||||
amdgpu_mes_alloc_gang_ctx_index(mes, queue);
|
||||
if (!uq_mgr->proc_ctx_allocated) {
|
||||
r = amdgpu_mes_alloc_proc_ctx_index(mes, &uq_mgr->proc_ctx_array_index);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to allocate userq process index err:%d\n", r);
|
||||
return r;
|
||||
}
|
||||
uq_mgr->proc_ctx_allocated = true;
|
||||
}
|
||||
|
||||
r = amdgpu_mes_alloc_gang_ctx_index(mes, &queue->gang_ctx_array_index);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to allocate userq gang index err:%d\n", r);
|
||||
return r;
|
||||
}
|
||||
queue_input.process_context_array_index = uq_mgr->proc_ctx_array_index;
|
||||
queue_input.gang_context_array_index = queue->gang_ctx_array_index;
|
||||
}
|
||||
amdgpu_mes_lock(&adev->mes);
|
||||
@@ -179,10 +193,8 @@ static int mes_userq_unmap(struct amdgpu_usermode_queue *queue)
|
||||
amdgpu_mes_lock(&adev->mes);
|
||||
r = adev->mes.funcs->remove_hw_queue(&adev->mes, &queue_input);
|
||||
amdgpu_mes_unlock(&adev->mes);
|
||||
if (mes->use_rs64mem) {
|
||||
amdgpu_mes_free_proc_ctx_index(mes, queue);
|
||||
amdgpu_mes_free_gang_ctx_index(mes, queue);
|
||||
}
|
||||
if (mes->use_rs64mem)
|
||||
amdgpu_mes_free_gang_ctx_index(mes, queue->gang_ctx_array_index);
|
||||
if (r)
|
||||
DRM_ERROR("Failed to unmap queue in HW, err (%d)\n", r);
|
||||
return r;
|
||||
@@ -205,7 +217,16 @@ int mes_userq_reset(struct amdgpu_usermode_queue *queue)
|
||||
amdgpu_mes_unlock(&adev->mes);
|
||||
if (r)
|
||||
return r;
|
||||
return mes_userq_unmap(queue);
|
||||
|
||||
/* mes_userq_unmap() does not update queue->state; mark it UNMAPPED so the
|
||||
* destroy path does not issue a second REMOVE_QUEUE for the removed queue.
|
||||
*/
|
||||
r = mes_userq_unmap(queue);
|
||||
if (!r) {
|
||||
trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_UNMAPPED);
|
||||
queue->state = AMDGPU_USERQ_STATE_UNMAPPED;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int mes_userq_reset_queue(struct amdgpu_device *adev,
|
||||
|
||||
@@ -1017,6 +1017,8 @@ static int mes_v11_0_set_hw_resources(struct amdgpu_mes *mes)
|
||||
mes_set_hw_res_pkt.enable_reg_active_poll = 1;
|
||||
mes_set_hw_res_pkt.enable_level_process_quantum_check = 1;
|
||||
mes_set_hw_res_pkt.oversubscription_timer = 50;
|
||||
if (adev->mes.use_rs64mem)
|
||||
mes_set_hw_res_pkt.use_rs64mem_for_proc_gang_ctx = 1;
|
||||
|
||||
if (amdgpu_mes_log_enable) {
|
||||
mes_set_hw_res_pkt.enable_mes_event_int_logging = 1;
|
||||
@@ -1952,6 +1954,8 @@ static int mes_v11_0_hw_init(struct amdgpu_ip_block *ip_block)
|
||||
if (adev->mes.ring[0].sched.ready)
|
||||
goto out;
|
||||
|
||||
adev->mes.use_rs64mem = true;
|
||||
|
||||
if (!adev->enable_mes_kiq) {
|
||||
if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) {
|
||||
r = mes_v11_0_load_microcode(adev,
|
||||
@@ -1971,11 +1975,12 @@ static int mes_v11_0_hw_init(struct amdgpu_ip_block *ip_block)
|
||||
|
||||
/* Allocate GPU buffer for array size query results */
|
||||
r = amdgpu_mes_rs64mem_init(&adev->mes);
|
||||
if (r)
|
||||
if (r) {
|
||||
dev_warn(adev->dev,
|
||||
"RS64 local memory init failed (%d),"
|
||||
"falling back to system memory path\n", r);
|
||||
|
||||
adev->mes.use_rs64mem = false;
|
||||
}
|
||||
r = mes_v11_0_set_hw_resources(&adev->mes);
|
||||
|
||||
if (r)
|
||||
@@ -1992,6 +1997,7 @@ static int mes_v11_0_hw_init(struct amdgpu_ip_block *ip_block)
|
||||
"Failed to query ctx array sizes (%d),"
|
||||
"disabling RS64 local memory\n", r);
|
||||
/* Continue without optimization - not fatal */
|
||||
adev->mes.use_rs64mem = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2033,10 +2039,6 @@ static int mes_v11_0_hw_init(struct amdgpu_ip_block *ip_block)
|
||||
|
||||
static int mes_v11_0_hw_fini(struct amdgpu_ip_block *ip_block)
|
||||
{
|
||||
struct amdgpu_device *adev = ip_block->adev;
|
||||
|
||||
if (adev->mes.use_rs64mem)
|
||||
amdgpu_mes_rs64mem_fini(&adev->mes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -993,10 +993,16 @@ static int mes_v12_0_set_hw_resources(struct amdgpu_mes *mes, int pipe)
|
||||
/*
|
||||
* Keep oversubscribe timer for sdma . When we have unmapped doorbell
|
||||
* handling support, other queue will not use the oversubscribe timer.
|
||||
* handling mode - 0: disabled; 1: basic version; 2: basic+ version
|
||||
* handling mode - 0: disabled; 1: basic; 2: basic+; 3: basic++
|
||||
*
|
||||
* Use basic+ (2): on an unmapped-queue doorbell ring MES reads the
|
||||
* per-queue CP_UNMAPPED_QUEUE bitmap and clears the ringing queue's
|
||||
* work_done so it is rescheduled. basic (1) only sets a coarse
|
||||
* level-wide ready flag without clearing work_done, so a queue that
|
||||
* rings after work_done was set is skipped and its work is lost.
|
||||
*/
|
||||
mes_set_hw_res_pkt.oversubscription_timer = mes_rev < 0x8b ? 0 : 50;
|
||||
mes_set_hw_res_pkt.unmapped_doorbell_handling = 1;
|
||||
mes_set_hw_res_pkt.unmapped_doorbell_handling = 2;
|
||||
|
||||
if (amdgpu_mes_log_enable) {
|
||||
mes_set_hw_res_pkt.enable_mes_event_int_logging = 1;
|
||||
|
||||
@@ -226,8 +226,10 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q,
|
||||
/* MES unit for quantum is 100ns */
|
||||
queue_input.process_quantum = KFD_MES_PROCESS_QUANTUM; /* Equivalent to 10ms. */
|
||||
queue_input.process_context_addr = pdd->proc_ctx_gpu_addr;
|
||||
queue_input.process_context_array_index = pdd->proc_ctx_array_index;
|
||||
queue_input.gang_quantum = KFD_MES_GANG_QUANTUM; /* Equivalent to 1ms */
|
||||
queue_input.gang_context_addr = q->gang_ctx_gpu_addr;
|
||||
queue_input.gang_context_array_index = q->gang_ctx_array_index;
|
||||
queue_input.inprocess_gang_priority = q->properties.priority;
|
||||
queue_input.gang_global_priority_level =
|
||||
AMDGPU_MES_PRIORITY_LEVEL_NORMAL;
|
||||
@@ -303,6 +305,7 @@ static int remove_queue_mes_on_reset_option(struct device_queue_manager *dqm, st
|
||||
queue_input.queue_type = convert_to_amdgpu_ring_type(q->properties.type);
|
||||
queue_input.remove_queue_after_reset = flush_mes_queue;
|
||||
queue_input.xcc_id = ffs(dqm->dev->xcc_mask) - 1;
|
||||
queue_input.gang_context_array_index = q->gang_ctx_array_index;
|
||||
|
||||
amdgpu_mes_lock(&adev->mes);
|
||||
r = adev->mes.funcs->remove_hw_queue(&adev->mes, &queue_input);
|
||||
|
||||
@@ -635,6 +635,7 @@ struct queue {
|
||||
void *gang_ctx_bo;
|
||||
uint64_t gang_ctx_gpu_addr;
|
||||
void *gang_ctx_cpu_ptr;
|
||||
uint32_t gang_ctx_array_index;
|
||||
|
||||
struct amdgpu_bo *wptr_bo_gart;
|
||||
};
|
||||
@@ -871,6 +872,8 @@ struct kfd_process_device {
|
||||
uint64_t proc_ctx_gpu_addr;
|
||||
void *proc_ctx_cpu_ptr;
|
||||
|
||||
uint32_t proc_ctx_array_index;
|
||||
|
||||
/* Tracks queue reset status */
|
||||
bool has_reset_queue;
|
||||
|
||||
@@ -895,7 +898,7 @@ struct svm_range_list {
|
||||
DECLARE_BITMAP(bitmap_supported, MAX_GPU_INSTANCE);
|
||||
struct task_struct *faulting_task;
|
||||
/* check point ts decides if page fault recovery need be dropped */
|
||||
uint64_t checkpoint_ts[MAX_GPU_INSTANCE];
|
||||
atomic64_t checkpoint_ts[MAX_GPU_INSTANCE];
|
||||
|
||||
/* Default granularity to use in buffer migration
|
||||
* and restoration of backing memory while handling
|
||||
|
||||
@@ -1215,9 +1215,12 @@ static void kfd_process_destroy_pdds(struct kfd_process *p)
|
||||
kfd_free_process_doorbells(pdd->dev->kfd, pdd);
|
||||
|
||||
if (pdd->dev->kfd->shared_resources.enable_mes &&
|
||||
pdd->proc_ctx_cpu_ptr)
|
||||
pdd->proc_ctx_cpu_ptr) {
|
||||
amdgpu_mes_free_proc_ctx_index(&pdd->dev->adev->mes,
|
||||
pdd->proc_ctx_array_index);
|
||||
amdgpu_amdkfd_free_kernel_mem(pdd->dev->adev,
|
||||
&pdd->proc_ctx_bo);
|
||||
}
|
||||
/*
|
||||
* before destroying pdd, make sure to report availability
|
||||
* for auto suspend
|
||||
|
||||
@@ -210,6 +210,7 @@ static void pqm_clean_queue_resource(struct process_queue_manager *pqm,
|
||||
}
|
||||
|
||||
if (dev->kfd->shared_resources.enable_mes) {
|
||||
amdgpu_mes_free_gang_ctx_index(&dev->adev->mes, pqn->q->gang_ctx_array_index);
|
||||
amdgpu_amdkfd_free_kernel_mem(dev->adev, &pqn->q->gang_ctx_bo);
|
||||
amdgpu_amdkfd_free_kernel_mem(dev->adev, (void **)&pqn->q->wptr_bo_gart);
|
||||
}
|
||||
@@ -282,7 +283,15 @@ static int init_user_queue(struct process_queue_manager *pqm,
|
||||
goto cleanup;
|
||||
}
|
||||
memset((*q)->gang_ctx_cpu_ptr, 0, AMDGPU_MES_GANG_CTX_SIZE);
|
||||
|
||||
/* Bind one MES gang context slot per queue (gang). */
|
||||
if (dev->adev->mes.use_rs64mem) {
|
||||
retval = amdgpu_mes_alloc_gang_ctx_index(&dev->adev->mes,
|
||||
&(*q)->gang_ctx_array_index);
|
||||
if (retval) {
|
||||
pr_err("failed to allocate gang context index slot\n");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
/* Starting with GFX11, wptr BOs must be mapped to GART for MES to determine work
|
||||
* on unmapped queues for usermode queue oversubscription (no aggregated doorbell)
|
||||
*/
|
||||
@@ -304,6 +313,7 @@ static int init_user_queue(struct process_queue_manager *pqm,
|
||||
return 0;
|
||||
|
||||
free_gang_ctx_bo:
|
||||
amdgpu_mes_free_gang_ctx_index(&dev->adev->mes, (*q)->gang_ctx_array_index);
|
||||
amdgpu_amdkfd_free_kernel_mem(dev->adev, &(*q)->gang_ctx_bo);
|
||||
cleanup:
|
||||
uninit_queue(*q);
|
||||
@@ -386,6 +396,17 @@ int pqm_create_queue(struct process_queue_manager *pqm,
|
||||
goto err_allocate_pqn;
|
||||
}
|
||||
memset(pdd->proc_ctx_cpu_ptr, 0, AMDGPU_MES_PROC_CTX_SIZE);
|
||||
/* Bind one MES process context slot to the whole process
|
||||
* (per device); every queue of this process reuses it.
|
||||
*/
|
||||
if (dev->adev->mes.use_rs64mem) {
|
||||
retval = amdgpu_mes_alloc_proc_ctx_index(&dev->adev->mes,
|
||||
&pdd->proc_ctx_array_index);
|
||||
if (retval) {
|
||||
dev_err(dev->adev->dev, "failed to allocate process context index\n");
|
||||
goto err_allocate_pqn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pqn = kzalloc_obj(*pqn);
|
||||
|
||||
@@ -102,7 +102,7 @@ static int kfd_queue_buffer_svm_get(struct kfd_process_device *pdd, u64 addr, u6
|
||||
mutex_lock(&p->svms.lock);
|
||||
|
||||
/*
|
||||
* range may split to multiple svm pranges aligned to granularity boundaery.
|
||||
* range may split to multiple svm pranges aligned to granularity boundary.
|
||||
*/
|
||||
while (size) {
|
||||
uint32_t gpuid, gpuidx;
|
||||
@@ -112,12 +112,11 @@ static int kfd_queue_buffer_svm_get(struct kfd_process_device *pdd, u64 addr, u6
|
||||
if (!prange)
|
||||
break;
|
||||
|
||||
if (!prange->mapped_to_gpu)
|
||||
break;
|
||||
|
||||
r = kfd_process_gpuid_from_node(p, pdd->dev, &gpuid, &gpuidx);
|
||||
if (r < 0)
|
||||
break;
|
||||
if (!test_bit(gpuidx, prange->bitmap_mapped))
|
||||
break;
|
||||
if (!test_bit(gpuidx, prange->bitmap_access) &&
|
||||
!test_bit(gpuidx, prange->bitmap_aip))
|
||||
break;
|
||||
|
||||
@@ -748,6 +748,48 @@ svm_range_check_attr(struct kfd_process *p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void svm_range_update_checkpoint_timestamp(struct kfd_process *p)
|
||||
{
|
||||
struct svm_range_list *svms;
|
||||
int i;
|
||||
|
||||
svms = &p->svms;
|
||||
|
||||
/* calculate time stamps that are used to decide which page faults need be
|
||||
* dropped or handled before unmap pages from gpu vm
|
||||
*/
|
||||
for_each_set_bit(i, svms->bitmap_supported, p->n_pdds) {
|
||||
struct kfd_process_device *pdd;
|
||||
struct amdgpu_device *adev;
|
||||
struct amdgpu_ih_ring *ih;
|
||||
uint32_t checkpoint_wptr;
|
||||
|
||||
pdd = p->pdds[i];
|
||||
if (!pdd)
|
||||
continue;
|
||||
|
||||
adev = pdd->dev->adev;
|
||||
|
||||
/* Check and drain ih1 ring if cam not available */
|
||||
if (!adev->irq.retry_cam_enabled && adev->irq.ih1.ring_size) {
|
||||
ih = &adev->irq.ih1;
|
||||
checkpoint_wptr = amdgpu_ih_get_wptr(adev, ih);
|
||||
if (ih->rptr != checkpoint_wptr) {
|
||||
atomic64_set(&svms->checkpoint_ts[i],
|
||||
amdgpu_ih_decode_iv_ts(adev, ih, checkpoint_wptr, -1));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if dev->irq.ih_soft is not empty */
|
||||
ih = &adev->irq.ih_soft;
|
||||
checkpoint_wptr = amdgpu_ih_get_wptr(adev, ih);
|
||||
if (ih->rptr != checkpoint_wptr)
|
||||
atomic64_set(&svms->checkpoint_ts[i],
|
||||
amdgpu_ih_decode_iv_ts(adev, ih, checkpoint_wptr, -1));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
svm_range_apply_attrs(struct kfd_process *p, struct svm_range *prange,
|
||||
uint32_t nattr, struct kfd_ioctl_svm_attribute *attrs,
|
||||
@@ -775,6 +817,8 @@ svm_range_apply_attrs(struct kfd_process *p, struct svm_range *prange,
|
||||
if (attrs[i].type == KFD_IOCTL_SVM_ATTR_NO_ACCESS) {
|
||||
bitmap_clear(prange->bitmap_access, gpuidx, 1);
|
||||
bitmap_clear(prange->bitmap_aip, gpuidx, 1);
|
||||
if (test_bit(gpuidx, prange->bitmap_mapped))
|
||||
bitmap_set(prange->bitmap_needs_unmap, gpuidx, 1);
|
||||
} else if (attrs[i].type == KFD_IOCTL_SVM_ATTR_ACCESS) {
|
||||
bitmap_set(prange->bitmap_access, gpuidx, 1);
|
||||
bitmap_clear(prange->bitmap_aip, gpuidx, 1);
|
||||
@@ -1065,9 +1109,10 @@ svm_range_split_adjust(struct svm_range *new, struct svm_range *old,
|
||||
new->prefetch_loc = old->prefetch_loc;
|
||||
new->actual_loc = old->actual_loc;
|
||||
new->granularity = old->granularity;
|
||||
new->mapped_to_gpu = old->mapped_to_gpu;
|
||||
new->mapping_done = old->mapping_done;
|
||||
bitmap_copy(new->bitmap_access, old->bitmap_access, MAX_GPU_INSTANCE);
|
||||
bitmap_copy(new->bitmap_aip, old->bitmap_aip, MAX_GPU_INSTANCE);
|
||||
bitmap_copy(new->bitmap_mapped, old->bitmap_mapped, MAX_GPU_INSTANCE);
|
||||
atomic_set(&new->queue_refcount, atomic_read(&old->queue_refcount));
|
||||
|
||||
return 0;
|
||||
@@ -1368,7 +1413,8 @@ svm_range_unmap_from_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm,
|
||||
|
||||
static int
|
||||
svm_range_unmap_from_gpus(struct svm_range *prange, unsigned long start,
|
||||
unsigned long last, uint32_t trigger)
|
||||
unsigned long last, unsigned long *bitmap_unmap,
|
||||
uint32_t trigger)
|
||||
{
|
||||
struct kfd_process_device *pdd;
|
||||
struct dma_fence *fence = NULL;
|
||||
@@ -1376,21 +1422,15 @@ svm_range_unmap_from_gpus(struct svm_range *prange, unsigned long start,
|
||||
uint32_t gpuidx;
|
||||
int r = 0;
|
||||
|
||||
if (!prange->mapped_to_gpu) {
|
||||
pr_debug("prange 0x%p [0x%lx 0x%lx] not mapped to GPU\n",
|
||||
prange, prange->start, prange->last);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (prange->start == start && prange->last == last) {
|
||||
pr_debug("unmap svms 0x%p prange 0x%p\n", prange->svms, prange);
|
||||
prange->mapped_to_gpu = false;
|
||||
}
|
||||
|
||||
p = container_of(prange->svms, struct kfd_process, svms);
|
||||
|
||||
for_each_or_bit(gpuidx, prange->bitmap_access, prange->bitmap_aip, MAX_GPU_INSTANCE) {
|
||||
pr_debug("unmap from gpu idx 0x%x\n", gpuidx);
|
||||
for_each_set_bit(gpuidx, bitmap_unmap, MAX_GPU_INSTANCE) {
|
||||
if (prange->start == start && prange->last == last) {
|
||||
pr_debug("unmap svms 0x%p prange 0x%p from gpu_idx 0x%x\n",
|
||||
prange->svms, prange, gpuidx);
|
||||
clear_bit(gpuidx, prange->bitmap_mapped);
|
||||
}
|
||||
|
||||
pdd = kfd_process_device_from_gpuidx(p, gpuidx);
|
||||
if (!pdd) {
|
||||
pr_debug("failed to find device idx %d\n", gpuidx);
|
||||
@@ -1543,6 +1583,8 @@ svm_range_map_to_gpus(struct svm_range *prange, unsigned long offset,
|
||||
continue;
|
||||
}
|
||||
|
||||
set_bit(gpuidx, prange->bitmap_mapped);
|
||||
|
||||
r = svm_range_map_to_gpu(pdd, prange, offset, npages, readonly,
|
||||
prange->dma_addr[gpuidx],
|
||||
bo_adev, wait ? &fence : NULL,
|
||||
@@ -1688,7 +1730,9 @@ static int svm_range_validate_and_map(struct mm_struct *mm,
|
||||
bitmap_zero(ctx->bitmap, MAX_GPU_INSTANCE);
|
||||
bitmap_set(ctx->bitmap, gpuidx, 1);
|
||||
} else if (ctx->process->xnack_enabled) {
|
||||
bitmap_copy(ctx->bitmap, prange->bitmap_aip, MAX_GPU_INSTANCE);
|
||||
/* Update mapping on already mapped or access in place GPU */
|
||||
bitmap_or(ctx->bitmap, prange->bitmap_mapped, prange->bitmap_aip,
|
||||
MAX_GPU_INSTANCE);
|
||||
|
||||
/* If prefetch range to GPU, or GPU retry fault migrate range to
|
||||
* GPU, which has ACCESS attribute to the range, create mapping
|
||||
@@ -1708,14 +1752,12 @@ static int svm_range_validate_and_map(struct mm_struct *mm,
|
||||
}
|
||||
|
||||
/*
|
||||
* If prange is already mapped or with always mapped flag,
|
||||
* update mapping on GPUs with ACCESS attribute
|
||||
* If prange with always mapped flag, update mapping on GPUs with
|
||||
* ACCESS attribute
|
||||
*/
|
||||
if (bitmap_empty(ctx->bitmap, MAX_GPU_INSTANCE)) {
|
||||
if (prange->mapped_to_gpu ||
|
||||
prange->flags & KFD_IOCTL_SVM_FLAG_GPU_ALWAYS_MAPPED)
|
||||
bitmap_copy(ctx->bitmap, prange->bitmap_access, MAX_GPU_INSTANCE);
|
||||
}
|
||||
if (prange->flags & KFD_IOCTL_SVM_FLAG_GPU_ALWAYS_MAPPED)
|
||||
bitmap_or(ctx->bitmap, ctx->bitmap, prange->bitmap_access,
|
||||
MAX_GPU_INSTANCE);
|
||||
} else {
|
||||
bitmap_or(ctx->bitmap, prange->bitmap_access,
|
||||
prange->bitmap_aip, MAX_GPU_INSTANCE);
|
||||
@@ -1781,6 +1823,7 @@ static int svm_range_validate_and_map(struct mm_struct *mm,
|
||||
e = min(end, prange->last);
|
||||
if (e >= s)
|
||||
r = svm_range_unmap_from_gpus(prange, s, e,
|
||||
prange->bitmap_mapped,
|
||||
KFD_SVM_UNMAP_TRIGGER_UNMAP_FROM_CPU);
|
||||
svm_range_unlock(prange);
|
||||
/* If unmap returns non-zero, we'll bail on the next for loop
|
||||
@@ -1843,7 +1886,9 @@ static int svm_range_validate_and_map(struct mm_struct *mm,
|
||||
}
|
||||
|
||||
if (!r && next == end)
|
||||
prange->mapped_to_gpu = true;
|
||||
prange->mapping_done = true;
|
||||
else
|
||||
prange->mapping_done = false;
|
||||
|
||||
svm_range_unlock(prange);
|
||||
|
||||
@@ -2013,10 +2058,10 @@ svm_range_evict(struct svm_range *prange, struct mm_struct *mm,
|
||||
if (!p->xnack_enabled ||
|
||||
(prange->flags & KFD_IOCTL_SVM_FLAG_GPU_ALWAYS_MAPPED)) {
|
||||
int evicted_ranges;
|
||||
bool mapped = prange->mapped_to_gpu;
|
||||
bool mapped = !bitmap_empty(prange->bitmap_mapped, MAX_GPU_INSTANCE);
|
||||
|
||||
list_for_each_entry(pchild, &prange->child_list, child_list) {
|
||||
if (!pchild->mapped_to_gpu)
|
||||
if (bitmap_empty(pchild->bitmap_mapped, MAX_GPU_INSTANCE))
|
||||
continue;
|
||||
mapped = true;
|
||||
mutex_lock_nested(&pchild->lock, 1);
|
||||
@@ -2065,13 +2110,14 @@ svm_range_evict(struct svm_range *prange, struct mm_struct *mm,
|
||||
s = max(start, pchild->start);
|
||||
l = min(last, pchild->last);
|
||||
if (l >= s)
|
||||
svm_range_unmap_from_gpus(pchild, s, l, trigger);
|
||||
svm_range_unmap_from_gpus(pchild, s, l, prange->bitmap_mapped,
|
||||
trigger);
|
||||
mutex_unlock(&pchild->lock);
|
||||
}
|
||||
s = max(start, prange->start);
|
||||
l = min(last, prange->last);
|
||||
if (l >= s)
|
||||
svm_range_unmap_from_gpus(prange, s, l, trigger);
|
||||
svm_range_unmap_from_gpus(prange, s, l, prange->bitmap_mapped, trigger);
|
||||
}
|
||||
|
||||
return r;
|
||||
@@ -2101,10 +2147,11 @@ static struct svm_range *svm_range_clone(struct svm_range *old)
|
||||
new->prefetch_loc = old->prefetch_loc;
|
||||
new->actual_loc = old->actual_loc;
|
||||
new->granularity = old->granularity;
|
||||
new->mapped_to_gpu = old->mapped_to_gpu;
|
||||
new->mapping_done = old->mapping_done;
|
||||
new->vram_pages = old->vram_pages;
|
||||
bitmap_copy(new->bitmap_access, old->bitmap_access, MAX_GPU_INSTANCE);
|
||||
bitmap_copy(new->bitmap_aip, old->bitmap_aip, MAX_GPU_INSTANCE);
|
||||
bitmap_copy(new->bitmap_mapped, old->bitmap_mapped, MAX_GPU_INSTANCE);
|
||||
atomic_set(&new->queue_refcount, atomic_read(&old->queue_refcount));
|
||||
|
||||
return new;
|
||||
@@ -2224,7 +2271,7 @@ svm_range_add(struct kfd_process *p, uint64_t start, uint64_t size,
|
||||
next_start = min(node->last, last) + 1;
|
||||
|
||||
if (svm_range_is_same_attrs(p, prange, nattr, attrs) &&
|
||||
prange->mapped_to_gpu) {
|
||||
prange->mapping_done) {
|
||||
/* nothing to do */
|
||||
} else if (node->start < start || node->last > last) {
|
||||
/* node intersects the update range and its attributes
|
||||
@@ -2545,7 +2592,6 @@ svm_range_unmap_from_cpu(struct mm_struct *mm, struct svm_range *prange,
|
||||
struct kfd_process *p;
|
||||
unsigned long s, l;
|
||||
bool unmap_parent;
|
||||
uint32_t i;
|
||||
|
||||
if (atomic_read(&prange->queue_refcount)) {
|
||||
int r;
|
||||
@@ -2565,38 +2611,7 @@ svm_range_unmap_from_cpu(struct mm_struct *mm, struct svm_range *prange,
|
||||
pr_debug("svms 0x%p prange 0x%p [0x%lx 0x%lx] [0x%lx 0x%lx]\n", svms,
|
||||
prange, prange->start, prange->last, start, last);
|
||||
|
||||
/* calculate time stamps that are used to decide which page faults need be
|
||||
* dropped or handled before unmap pages from gpu vm
|
||||
*/
|
||||
for_each_set_bit(i, svms->bitmap_supported, p->n_pdds) {
|
||||
struct kfd_process_device *pdd;
|
||||
struct amdgpu_device *adev;
|
||||
struct amdgpu_ih_ring *ih;
|
||||
uint32_t checkpoint_wptr;
|
||||
|
||||
pdd = p->pdds[i];
|
||||
if (!pdd)
|
||||
continue;
|
||||
|
||||
adev = pdd->dev->adev;
|
||||
|
||||
/* Check and drain ih1 ring if cam not available */
|
||||
if (!adev->irq.retry_cam_enabled && adev->irq.ih1.ring_size) {
|
||||
ih = &adev->irq.ih1;
|
||||
checkpoint_wptr = amdgpu_ih_get_wptr(adev, ih);
|
||||
if (ih->rptr != checkpoint_wptr) {
|
||||
svms->checkpoint_ts[i] =
|
||||
amdgpu_ih_decode_iv_ts(adev, ih, checkpoint_wptr, -1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if dev->irq.ih_soft is not empty */
|
||||
ih = &adev->irq.ih_soft;
|
||||
checkpoint_wptr = amdgpu_ih_get_wptr(adev, ih);
|
||||
if (ih->rptr != checkpoint_wptr)
|
||||
svms->checkpoint_ts[i] = amdgpu_ih_decode_iv_ts(adev, ih, checkpoint_wptr, -1);
|
||||
}
|
||||
svm_range_update_checkpoint_timestamp(p);
|
||||
|
||||
unmap_parent = start <= prange->start && last >= prange->last;
|
||||
|
||||
@@ -2605,14 +2620,14 @@ svm_range_unmap_from_cpu(struct mm_struct *mm, struct svm_range *prange,
|
||||
s = max(start, pchild->start);
|
||||
l = min(last, pchild->last);
|
||||
if (l >= s)
|
||||
svm_range_unmap_from_gpus(pchild, s, l, trigger);
|
||||
svm_range_unmap_from_gpus(pchild, s, l, prange->bitmap_mapped, trigger);
|
||||
svm_range_unmap_split(prange, pchild, start, last);
|
||||
mutex_unlock(&pchild->lock);
|
||||
}
|
||||
s = max(start, prange->start);
|
||||
l = min(last, prange->last);
|
||||
if (l >= s)
|
||||
svm_range_unmap_from_gpus(prange, s, l, trigger);
|
||||
svm_range_unmap_from_gpus(prange, s, l, prange->bitmap_mapped, trigger);
|
||||
svm_range_unmap_split(prange, prange, start, last);
|
||||
|
||||
if (unmap_parent)
|
||||
@@ -3043,6 +3058,7 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
|
||||
struct svm_range *prange;
|
||||
struct kfd_process *p;
|
||||
ktime_t timestamp = ktime_get_boottime();
|
||||
uint64_t checkpoint_ts;
|
||||
struct kfd_node *node;
|
||||
int32_t best_loc;
|
||||
int32_t gpuid, gpuidx = MAX_GPU_INSTANCE;
|
||||
@@ -3105,9 +3121,11 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
|
||||
retry_write_locked:
|
||||
mutex_lock(&svms->lock);
|
||||
|
||||
checkpoint_ts = atomic64_read(&svms->checkpoint_ts[gpuidx]);
|
||||
|
||||
/* check if this page fault time stamp is before svms->checkpoint_ts */
|
||||
if (svms->checkpoint_ts[gpuidx] != 0) {
|
||||
if (amdgpu_ih_ts_after_or_equal(ts, svms->checkpoint_ts[gpuidx])) {
|
||||
if (checkpoint_ts) {
|
||||
if (amdgpu_ih_ts_after_or_equal(ts, checkpoint_ts)) {
|
||||
pr_debug("draining retry fault, drop fault 0x%llx\n", addr);
|
||||
if (write_locked)
|
||||
mmap_write_downgrade(mm);
|
||||
@@ -3117,7 +3135,7 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid,
|
||||
/* ts is after svms->checkpoint_ts now, reset svms->checkpoint_ts
|
||||
* to zero to avoid following ts wrap around give wrong comparing
|
||||
*/
|
||||
svms->checkpoint_ts[gpuidx] = 0;
|
||||
atomic64_set(&svms->checkpoint_ts[gpuidx], 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3711,6 +3729,25 @@ int svm_range_evict_svm_bo(struct amdgpu_bo *bo)
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool svm_range_needs_unmap(struct kfd_process *p, struct svm_range *prange)
|
||||
{
|
||||
if (bitmap_empty(prange->bitmap_needs_unmap, MAX_GPU_INSTANCE))
|
||||
return false;
|
||||
|
||||
pr_debug("prange 0x%p no access set for [0x%lx 0x%lx]\n",
|
||||
prange, prange->start, prange->last);
|
||||
|
||||
svm_range_update_checkpoint_timestamp(p);
|
||||
|
||||
svm_range_unmap_from_gpus(prange, prange->start,
|
||||
prange->last, prange->bitmap_needs_unmap,
|
||||
KFD_SVM_UNMAP_TRIGGER_UNMAP_FROM_CPU);
|
||||
|
||||
bitmap_clear(prange->bitmap_needs_unmap, 0, MAX_GPU_INSTANCE);
|
||||
|
||||
return bitmap_empty(prange->bitmap_mapped, MAX_GPU_INSTANCE);
|
||||
}
|
||||
|
||||
static int
|
||||
svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm,
|
||||
uint64_t start, uint64_t size, uint32_t nattr,
|
||||
@@ -3766,10 +3803,10 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm,
|
||||
svm_range_add_to_svms(prange);
|
||||
svm_range_add_notifier_locked(mm, prange);
|
||||
}
|
||||
list_for_each_entry(prange, &update_list, update_list) {
|
||||
|
||||
list_for_each_entry(prange, &update_list, update_list)
|
||||
svm_range_apply_attrs(p, prange, nattr, attrs, &update_mapping);
|
||||
/* TODO: unmap ranges from GPU that lost access */
|
||||
}
|
||||
|
||||
update_mapping |= !p->xnack_enabled && !list_empty(&remap_list);
|
||||
|
||||
list_for_each_entry_safe(prange, next, &remove_list, update_list) {
|
||||
@@ -3790,6 +3827,9 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm,
|
||||
list_for_each_entry(prange, &update_list, update_list) {
|
||||
bool migrated;
|
||||
|
||||
if (svm_range_needs_unmap(p, prange))
|
||||
continue;
|
||||
|
||||
mutex_lock(&prange->migrate_mutex);
|
||||
|
||||
r = svm_range_trigger_migration(mm, prange, &migrated);
|
||||
@@ -3798,7 +3838,7 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm,
|
||||
|
||||
if (migrated && (!p->xnack_enabled ||
|
||||
(prange->flags & KFD_IOCTL_SVM_FLAG_GPU_ALWAYS_MAPPED)) &&
|
||||
prange->mapped_to_gpu) {
|
||||
!bitmap_empty(prange->bitmap_mapped, MAX_GPU_INSTANCE)) {
|
||||
pr_debug("restore_work will update mappings of GPUs\n");
|
||||
mutex_unlock(&prange->migrate_mutex);
|
||||
continue;
|
||||
@@ -3809,7 +3849,8 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm,
|
||||
continue;
|
||||
}
|
||||
|
||||
flush_tlb = !migrated && update_mapping && prange->mapped_to_gpu;
|
||||
flush_tlb = !migrated && update_mapping &&
|
||||
!bitmap_empty(prange->bitmap_mapped, MAX_GPU_INSTANCE);
|
||||
|
||||
r = svm_range_validate_and_map(mm, prange->start, prange->last, prange,
|
||||
MAX_GPU_INSTANCE, true, true, flush_tlb);
|
||||
@@ -3823,11 +3864,13 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm,
|
||||
}
|
||||
|
||||
list_for_each_entry(prange, &remap_list, update_list) {
|
||||
flush_tlb = !bitmap_empty(prange->bitmap_mapped, MAX_GPU_INSTANCE);
|
||||
|
||||
pr_debug("Remapping prange 0x%p [0x%lx 0x%lx]\n",
|
||||
prange, prange->start, prange->last);
|
||||
mutex_lock(&prange->migrate_mutex);
|
||||
r = svm_range_validate_and_map(mm, prange->start, prange->last, prange,
|
||||
MAX_GPU_INSTANCE, true, true, prange->mapped_to_gpu);
|
||||
MAX_GPU_INSTANCE, true, true, flush_tlb);
|
||||
if (r)
|
||||
pr_debug("failed %d on remap svm range\n", r);
|
||||
mutex_unlock(&prange->migrate_mutex);
|
||||
|
||||
@@ -99,6 +99,9 @@ struct svm_work_list_item {
|
||||
* @child_list: list header for split ranges which are not added to svms yet
|
||||
* @bitmap_access: index bitmap of GPUs which can access the range
|
||||
* @bitmap_aip: index bitmap of GPUs which can access the range in place
|
||||
* @bitmap_needs_unmap: index bitmap of GPUs which currently set NO_ACCESS
|
||||
* @bitmap_mapped: index bitmap of GPUs which currently have the range mapped
|
||||
* @mapping_done: true if range_validate_and_map complete successfully
|
||||
*
|
||||
* Data structure for virtual memory range shared by CPU and GPUs, it can be
|
||||
* allocated from system memory ram or device vram, and migrate from ram to vram
|
||||
@@ -134,7 +137,9 @@ struct svm_range {
|
||||
struct list_head child_list;
|
||||
DECLARE_BITMAP(bitmap_access, MAX_GPU_INSTANCE);
|
||||
DECLARE_BITMAP(bitmap_aip, MAX_GPU_INSTANCE);
|
||||
bool mapped_to_gpu;
|
||||
DECLARE_BITMAP(bitmap_needs_unmap, MAX_GPU_INSTANCE);
|
||||
DECLARE_BITMAP(bitmap_mapped, MAX_GPU_INSTANCE);
|
||||
bool mapping_done;
|
||||
atomic_t queue_refcount;
|
||||
};
|
||||
|
||||
|
||||
@@ -607,6 +607,11 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
|
||||
init_data.flags.unify_link_enc_assignment = true;
|
||||
init_data.flags.usb4_bw_alloc_support = true;
|
||||
}
|
||||
|
||||
/* DCN201 audio desyncs using DP SS */
|
||||
if (adev->apu_flags & AMD_APU_IS_CYAN_SKILLFISH2)
|
||||
init_data.flags.ignore_dpref_ss = true;
|
||||
|
||||
retrieve_dmi_info(&adev->dm);
|
||||
if (adev->dm.edp0_on_dp1_quirk)
|
||||
init_data.flags.support_edp0_on_dp1 = true;
|
||||
@@ -1011,6 +1016,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev)
|
||||
case IP_VERSION(4, 0, 1):
|
||||
case IP_VERSION(4, 2, 0):
|
||||
case IP_VERSION(4, 2, 1):
|
||||
case IP_VERSION(6, 0, 0):
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
@@ -2410,6 +2416,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
|
||||
case IP_VERSION(4, 0, 1):
|
||||
case IP_VERSION(4, 2, 0):
|
||||
case IP_VERSION(4, 2, 1):
|
||||
case IP_VERSION(6, 0, 0):
|
||||
if (amdgpu_dm_register_outbox_irq_handlers(dm->adev)) {
|
||||
drm_err(adev_to_drm(adev), "DM: Failed to initialize IRQ\n");
|
||||
goto fail;
|
||||
@@ -2436,6 +2443,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
|
||||
case IP_VERSION(4, 0, 1):
|
||||
case IP_VERSION(4, 2, 0):
|
||||
case IP_VERSION(4, 2, 1):
|
||||
case IP_VERSION(6, 0, 0):
|
||||
psr_feature_enabled = true;
|
||||
break;
|
||||
default:
|
||||
@@ -2455,6 +2463,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
|
||||
case IP_VERSION(3, 6, 0):
|
||||
case IP_VERSION(4, 2, 0):
|
||||
case IP_VERSION(4, 2, 1):
|
||||
case IP_VERSION(6, 0, 0):
|
||||
replay_feature_enabled = true;
|
||||
break;
|
||||
|
||||
@@ -2617,6 +2626,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
|
||||
case IP_VERSION(4, 0, 1):
|
||||
case IP_VERSION(4, 2, 0):
|
||||
case IP_VERSION(4, 2, 1):
|
||||
case IP_VERSION(6, 0, 0):
|
||||
if (amdgpu_dm_dcn10_register_irq_handlers(dm->adev)) {
|
||||
drm_err(adev_to_drm(adev), "DM: Failed to initialize IRQ\n");
|
||||
goto fail;
|
||||
@@ -2829,6 +2839,7 @@ static int dm_early_init(struct amdgpu_ip_block *ip_block)
|
||||
case IP_VERSION(4, 0, 1):
|
||||
case IP_VERSION(4, 2, 0):
|
||||
case IP_VERSION(4, 2, 1):
|
||||
case IP_VERSION(6, 0, 0):
|
||||
adev->mode_info.num_crtc = 4;
|
||||
adev->mode_info.num_hpd = 4;
|
||||
adev->mode_info.num_dig = 4;
|
||||
@@ -4655,21 +4666,19 @@ static void dm_set_writeback(struct amdgpu_display_manager *dm,
|
||||
wb_info = kzalloc_obj(*wb_info);
|
||||
if (!wb_info) {
|
||||
drm_err(adev_to_drm(adev), "Failed to allocate wb_info\n");
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
acrtc = to_amdgpu_crtc(wb_conn->encoder.crtc);
|
||||
if (!acrtc) {
|
||||
drm_err(adev_to_drm(adev), "no amdgpu_crtc found\n");
|
||||
kfree(wb_info);
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
afb = to_amdgpu_framebuffer(new_con_state->writeback_job->fb);
|
||||
if (!afb) {
|
||||
drm_err(adev_to_drm(adev), "No amdgpu_framebuffer found\n");
|
||||
kfree(wb_info);
|
||||
return;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
@@ -4679,6 +4688,11 @@ static void dm_set_writeback(struct amdgpu_display_manager *dm,
|
||||
}
|
||||
}
|
||||
|
||||
if (!pipe) {
|
||||
drm_err(adev_to_drm(adev), "No pipe found for stream\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* fill in wb_info */
|
||||
wb_info->wb_enabled = true;
|
||||
|
||||
@@ -4752,6 +4766,9 @@ static void dm_set_writeback(struct amdgpu_display_manager *dm,
|
||||
WARN_ON(drm_crtc_vblank_get(&acrtc->base));
|
||||
acrtc->wb_frame_done = false;
|
||||
acrtc->wb_pending = true;
|
||||
|
||||
cleanup:
|
||||
kfree(wb_info);
|
||||
}
|
||||
|
||||
static void amdgpu_dm_update_hdcp(struct drm_atomic_commit *state)
|
||||
@@ -6330,12 +6347,9 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
|
||||
if (dm_new_crtc_state->cursor_mode == DM_CURSOR_OVERLAY_MODE)
|
||||
continue;
|
||||
|
||||
/* Check if rotation or scaling is enabled on DCN401 */
|
||||
if ((drm_plane_mask(crtc->cursor) &
|
||||
new_crtc_state->plane_mask) &&
|
||||
(amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 1) ||
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0) ||
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 0, 1))) {
|
||||
/* Check if rotation or scaling is enabled on DCN 4x and above */
|
||||
if ((drm_plane_mask(crtc->cursor) & new_crtc_state->plane_mask) &&
|
||||
(amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(4, 0, 1))) {
|
||||
new_cursor_state = drm_atomic_get_new_plane_state(state, crtc->cursor);
|
||||
|
||||
is_rotated = new_cursor_state &&
|
||||
|
||||
@@ -857,8 +857,6 @@ struct amdgpu_dm_connector {
|
||||
struct mutex hpd_lock;
|
||||
|
||||
bool fake_enable;
|
||||
bool force_yuv420_output;
|
||||
bool force_yuv422_output;
|
||||
uint8_t force_yuv_pixel_format;
|
||||
struct dsc_preferred_settings dsc_settings;
|
||||
struct psr_caps psr_caps;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
struct amdgpu_device;
|
||||
struct drm_device;
|
||||
struct drm_atomic_state;
|
||||
struct drm_atomic_commit;
|
||||
struct drm_connector;
|
||||
struct audio_info;
|
||||
struct dc_sink;
|
||||
|
||||
@@ -147,7 +147,7 @@ STATIC_IFN_KUNIT int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
|
||||
int max_bpc = conn_state->max_requested_bpc;
|
||||
|
||||
is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) &&
|
||||
aconnector->force_yuv420_output;
|
||||
aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420;
|
||||
color_depth = amdgpu_dm_convert_color_depth_from_display_info(connector,
|
||||
is_y420,
|
||||
max_bpc);
|
||||
@@ -855,16 +855,15 @@ STATIC_IFN_KUNIT void fill_stream_properties_from_drm_display_mode(
|
||||
const struct drm_connector *connector,
|
||||
const struct drm_connector_state *connector_state,
|
||||
const struct dc_stream_state *old_stream,
|
||||
int requested_bpc)
|
||||
int requested_bpc,
|
||||
enum dc_pixel_encoding requested_encoding,
|
||||
bool is_hdmi_ep)
|
||||
{
|
||||
bool is_dp_or_hdmi = dc_is_hdmi_signal(stream->signal) || dc_is_dp_signal(stream->signal);
|
||||
struct dc_crtc_timing *timing_out = &stream->timing;
|
||||
const struct drm_display_info *info = &connector->display_info;
|
||||
struct amdgpu_dm_connector *aconnector = NULL;
|
||||
struct hdmi_vendor_infoframe hv_frame;
|
||||
struct hdmi_avi_infoframe avi_frame;
|
||||
bool want_420;
|
||||
bool want_422;
|
||||
ssize_t err;
|
||||
|
||||
if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
|
||||
@@ -878,40 +877,13 @@ STATIC_IFN_KUNIT void fill_stream_properties_from_drm_display_mode(
|
||||
timing_out->v_border_top = 0;
|
||||
timing_out->v_border_bottom = 0;
|
||||
|
||||
want_420 = (aconnector && aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420) ||
|
||||
(connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR420);
|
||||
want_422 = (aconnector && aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR422) ||
|
||||
(connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR422);
|
||||
|
||||
if (drm_mode_is_420_only(info, mode_in) &&
|
||||
(want_420 || connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO)) {
|
||||
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
|
||||
} else if (drm_mode_is_420_also(info, mode_in) && want_420) {
|
||||
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
|
||||
} else if ((info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422)) &&
|
||||
want_422 && is_dp_or_hdmi) {
|
||||
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR422;
|
||||
} else if (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR444 &&
|
||||
(info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) &&
|
||||
is_dp_or_hdmi) {
|
||||
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;
|
||||
} else if (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_RGB444 ||
|
||||
connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO) {
|
||||
timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
|
||||
} else {
|
||||
/*
|
||||
* If a format was explicitly requested but the requested format
|
||||
* can't be satisfied, set it to an invalid value so that an
|
||||
* error bubbles up to userspace. This way, userspace knows it
|
||||
* needs to make a better choice.
|
||||
*/
|
||||
if (connector_state->color_format != DRM_CONNECTOR_COLOR_FORMAT_AUTO)
|
||||
timing_out->pixel_encoding = PIXEL_ENCODING_UNDEFINED;
|
||||
else if (drm_mode_is_420_only(info, mode_in))
|
||||
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
|
||||
else
|
||||
timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
|
||||
}
|
||||
/*
|
||||
* The pixel encoding to use is decided entirely by the caller (see
|
||||
* amdgpu_dm_create_validate_stream_for_sink()), which enumerates only
|
||||
* the encodings the sink actually advertises. This helper must not
|
||||
* second-guess that choice; it simply applies it.
|
||||
*/
|
||||
timing_out->pixel_encoding = requested_encoding;
|
||||
|
||||
timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE;
|
||||
timing_out->display_color_depth = amdgpu_dm_convert_color_depth_from_display_info(
|
||||
@@ -977,14 +949,15 @@ STATIC_IFN_KUNIT void fill_stream_properties_from_drm_display_mode(
|
||||
|
||||
stream->out_transfer_func.type = TF_TYPE_PREDEFINED;
|
||||
stream->out_transfer_func.tf = TRANSFER_FUNCTION_SRGB;
|
||||
if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) {
|
||||
if (!adjust_colour_depth_from_display_info(timing_out, info) &&
|
||||
drm_mode_is_420_also(info, mode_in) &&
|
||||
timing_out->pixel_encoding != PIXEL_ENCODING_YCBCR420) {
|
||||
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
|
||||
adjust_colour_depth_from_display_info(timing_out, info);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clamp the HDMI colour depth to what the sink's max TMDS clock
|
||||
* allows. The pixel encoding is fixed by the caller and must not be
|
||||
* changed here: the caller already enumerates YCbCr420 as its own
|
||||
* candidate, so silently switching to it would hide an enumeration
|
||||
* bug and produce a stream the caller never asked to validate.
|
||||
*/
|
||||
if (is_hdmi_ep)
|
||||
adjust_colour_depth_from_display_info(timing_out, info);
|
||||
|
||||
stream->output_color_space = amdgpu_dm_get_output_color_space(timing_out, connector_state);
|
||||
stream->content_type = get_output_content_type(connector_state);
|
||||
@@ -1451,7 +1424,9 @@ create_stream_for_sink(struct drm_connector *connector,
|
||||
const struct drm_display_mode *drm_mode,
|
||||
const struct dm_connector_state *dm_state,
|
||||
const struct dc_stream_state *old_stream,
|
||||
int requested_bpc)
|
||||
int requested_bpc,
|
||||
enum dc_pixel_encoding requested_encoding,
|
||||
bool is_hdmi_ep)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct amdgpu_dm_connector *aconnector = NULL;
|
||||
@@ -1562,11 +1537,11 @@ create_stream_for_sink(struct drm_connector *connector,
|
||||
if (!scale || mode_refresh != preferred_refresh)
|
||||
fill_stream_properties_from_drm_display_mode(
|
||||
stream, &mode, connector, con_state, NULL,
|
||||
requested_bpc);
|
||||
requested_bpc, requested_encoding, is_hdmi_ep);
|
||||
else
|
||||
fill_stream_properties_from_drm_display_mode(
|
||||
stream, &mode, connector, con_state, old_stream,
|
||||
requested_bpc);
|
||||
requested_bpc, requested_encoding, is_hdmi_ep);
|
||||
|
||||
/* The rest isn't needed for writeback connectors */
|
||||
if (!aconnector)
|
||||
@@ -2271,13 +2246,32 @@ amdgpu_dm_create_validate_stream_for_sink(struct drm_connector *connector,
|
||||
const struct dm_connector_state *dm_state,
|
||||
const struct dc_stream_state *old_stream)
|
||||
{
|
||||
/*
|
||||
* Ordered lists of the encodings and bit depths we are willing to
|
||||
* validate, best quality/bandwidth first. The per-sink masks built
|
||||
* below gate which of these entries are actually attempted.
|
||||
*/
|
||||
static const enum dc_pixel_encoding encoding_order[] = {
|
||||
PIXEL_ENCODING_YCBCR444,
|
||||
PIXEL_ENCODING_RGB,
|
||||
PIXEL_ENCODING_YCBCR422,
|
||||
PIXEL_ENCODING_YCBCR420,
|
||||
};
|
||||
static const u8 bpc_order[] = { 16, 12, 10, 8, 6 };
|
||||
|
||||
struct amdgpu_dm_connector *aconnector = NULL;
|
||||
struct amdgpu_device *adev = drm_to_adev(connector->dev);
|
||||
struct dc_stream_state *stream;
|
||||
const struct drm_display_info *info = &connector->display_info;
|
||||
struct dc_stream_state *stream = NULL;
|
||||
const struct drm_connector_state *drm_state = dm_state ? &dm_state->base : NULL;
|
||||
int requested_bpc = drm_state ? drm_state->max_requested_bpc : 8;
|
||||
enum dc_status dc_result = DC_OK;
|
||||
uint8_t bpc_limit = 6;
|
||||
enum signal_type signal = SIGNAL_TYPE_NONE;
|
||||
bool want_420, want_422, is_dp_or_hdmi;
|
||||
u32 encoding_mask = 0;
|
||||
u32 bpc_mask = 0;
|
||||
bool is_hdmi_ep = false;
|
||||
unsigned int i, j;
|
||||
|
||||
if (!dm_state)
|
||||
return NULL;
|
||||
@@ -2285,90 +2279,181 @@ amdgpu_dm_create_validate_stream_for_sink(struct drm_connector *connector,
|
||||
if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
|
||||
aconnector = to_amdgpu_dm_connector(connector);
|
||||
|
||||
if (aconnector &&
|
||||
(aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_TYPE_A ||
|
||||
aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_FRL ||
|
||||
aconnector->dc_link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER))
|
||||
bpc_limit = 8;
|
||||
|
||||
do {
|
||||
drm_dbg_kms(connector->dev, "Trying with %d bpc\n", requested_bpc);
|
||||
stream = create_stream_for_sink(connector, drm_mode,
|
||||
dm_state, old_stream,
|
||||
requested_bpc);
|
||||
if (stream == NULL) {
|
||||
/*
|
||||
* Writeback connectors have no sink EDID to enumerate against. They
|
||||
* only ever use RGB at the requested depth, so build and validate a
|
||||
* single stream directly and return it (dc_validate_stream() is not
|
||||
* meaningful for the writeback path).
|
||||
*/
|
||||
if (!aconnector) {
|
||||
stream = create_stream_for_sink(connector, drm_mode, dm_state,
|
||||
old_stream, requested_bpc,
|
||||
PIXEL_ENCODING_RGB, is_hdmi_ep);
|
||||
if (!stream)
|
||||
drm_err(adev_to_drm(adev), "Failed to create stream for sink!\n");
|
||||
break;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
dc_result = dc_validate_stream(adev->dm.dc, stream);
|
||||
signal = aconnector->dc_link->connector_signal;
|
||||
|
||||
if (!aconnector) /* writeback connector */
|
||||
return stream;
|
||||
/*
|
||||
* Determine whether this is a native HDMI sink or a DP->HDMI dongle.
|
||||
* Since we check for it a few times below, cache the result.
|
||||
*/
|
||||
is_hdmi_ep = (signal == SIGNAL_TYPE_HDMI_TYPE_A ||
|
||||
signal == SIGNAL_TYPE_HDMI_FRL ||
|
||||
aconnector->dc_link->dpcd_caps.dongle_type ==
|
||||
DISPLAY_DONGLE_DP_HDMI_CONVERTER);
|
||||
is_dp_or_hdmi = dc_is_hdmi_signal(signal) || dc_is_dp_signal(signal);
|
||||
|
||||
if (dc_result == DC_OK && stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
|
||||
dc_result = dm_dp_mst_is_port_support_mode(aconnector, stream);
|
||||
/*
|
||||
* Build the set of pixel encodings this sink advertises, so we only
|
||||
* ever validate combinations the display can actually accept. Ordered
|
||||
* best-first: RGB / YCbCr444 (full bandwidth) -> YCbCr422 -> YCbCr420.
|
||||
*
|
||||
* - RGB is the mandatory baseline and always available.
|
||||
* - YCbCr444 is only meaningful for native HDMI sinks.
|
||||
* - A 420-only mode collapses the mask to YCbCr420 alone.
|
||||
* - The debugfs force_yuv_pixel_format override pins the encoding to a
|
||||
* single dc_pixel_encoding when set (PIXEL_ENCODING_UNDEFINED means
|
||||
* "no override"). An explicit YCbCr420 force is honoured even on
|
||||
* modes the sink only lists as RGB/4:4:4 capable
|
||||
* (drm_mode_is_420_also() clear), as required for HDMI compliance
|
||||
* testing; dc_validate_stream() still rejects anything the link
|
||||
* genuinely cannot carry. The YCbCr422/YCbCr444 forces stay gated on
|
||||
* the sink's advertised caps.
|
||||
*/
|
||||
want_420 = (aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420) ||
|
||||
(drm_state && drm_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR420);
|
||||
want_422 = (aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR422) ||
|
||||
(drm_state && drm_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR422);
|
||||
|
||||
if (dc_result == DC_OK)
|
||||
dc_result = dm_validate_stream_and_context(adev->dm.dc, stream);
|
||||
if (drm_mode_is_420_only(info, drm_mode) &&
|
||||
(want_420 || (drm_state && drm_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO))) {
|
||||
encoding_mask = BIT(PIXEL_ENCODING_YCBCR420);
|
||||
} else if (drm_mode_is_420_also(info, drm_mode) && want_420) {
|
||||
encoding_mask = BIT(PIXEL_ENCODING_YCBCR420);
|
||||
} else if ((info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422)) &&
|
||||
want_422 && is_dp_or_hdmi) {
|
||||
encoding_mask = BIT(PIXEL_ENCODING_YCBCR422);
|
||||
} else if (((aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR444) ||
|
||||
(drm_state && drm_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR444)) &&
|
||||
(info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) &&
|
||||
is_dp_or_hdmi) {
|
||||
encoding_mask = BIT(PIXEL_ENCODING_YCBCR444);
|
||||
} else if (drm_state && drm_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_RGB444) {
|
||||
encoding_mask = BIT(PIXEL_ENCODING_RGB);
|
||||
} else {
|
||||
encoding_mask = BIT(PIXEL_ENCODING_RGB);
|
||||
|
||||
if (dc_result == DC_OK)
|
||||
dc_result = dm_validate_stream_color_format(drm_state, stream);
|
||||
if ((info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) &&
|
||||
is_hdmi_ep)
|
||||
encoding_mask |= BIT(PIXEL_ENCODING_YCBCR444);
|
||||
|
||||
if (dc_result != DC_OK) {
|
||||
drm_dbg_kms(connector->dev, "Pruned mode %d x %d (clk %d) %s %s -- %s\n",
|
||||
if (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
|
||||
encoding_mask |= BIT(PIXEL_ENCODING_YCBCR422);
|
||||
|
||||
if (drm_mode_is_420_also(info, drm_mode))
|
||||
encoding_mask |= BIT(PIXEL_ENCODING_YCBCR420);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build the set of bit depths to try, high-to-low. Start from the
|
||||
* atomic-requested cap and clear anything the sink cannot do:
|
||||
*
|
||||
* - Never exceed the requested bpc.
|
||||
* - HDMI/FRL and DP->HDMI dongles have no defined 6 bpc mode.
|
||||
* - Any depth above the EDID-reported bpc is dropped.
|
||||
*
|
||||
* amdgpu_dm_convert_color_depth_from_display_info() applies the final
|
||||
* per-encoding cap (e.g. YCbCr420 deep-colour limits) when the stream
|
||||
* is built, so this mask only needs the coarse sink limits.
|
||||
*/
|
||||
for (j = 0; j < ARRAY_SIZE(bpc_order); j++) {
|
||||
u8 bpc = bpc_order[j];
|
||||
|
||||
if (requested_bpc > 0 && bpc > requested_bpc)
|
||||
continue;
|
||||
|
||||
if (bpc == 6 && is_hdmi_ep)
|
||||
continue;
|
||||
|
||||
if (info->bpc && bpc > info->bpc)
|
||||
continue;
|
||||
|
||||
bpc_mask |= BIT(bpc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enumerate the supported (encoding, bpc) combinations in priority
|
||||
* order and return the first that validates. Because the masks only
|
||||
* contain sink-supported entries, this is generic across connector
|
||||
* types and needs no encoding-specific fallback afterwards.
|
||||
*
|
||||
* The selection lives entirely on the stack and is passed by value to
|
||||
* create_stream_for_sink(); no shared connector state is mutated. This
|
||||
* matters because this helper runs concurrently from the connector
|
||||
* probe worker (->mode_valid) and from a compositor's atomic check on
|
||||
* the same connector.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(encoding_order); i++) {
|
||||
enum dc_pixel_encoding enc = encoding_order[i];
|
||||
|
||||
if (!(encoding_mask & BIT(enc)))
|
||||
continue;
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(bpc_order); j++) {
|
||||
u8 bpc = bpc_order[j];
|
||||
|
||||
if (!(bpc_mask & BIT(bpc)))
|
||||
continue;
|
||||
|
||||
drm_dbg_kms(connector->dev,
|
||||
"Trying %s with %d bpc (encoding_mask=0x%x bpc_mask=0x%x requested_bpc=%d drm max_bpc)\n",
|
||||
dc_pixel_encoding_to_str(enc), bpc,
|
||||
encoding_mask, bpc_mask, requested_bpc);
|
||||
|
||||
stream = create_stream_for_sink(connector, drm_mode,
|
||||
dm_state, old_stream,
|
||||
bpc, enc, is_hdmi_ep);
|
||||
if (stream == NULL) {
|
||||
drm_err(adev_to_drm(adev), "Failed to create stream for sink!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dc_result = dc_validate_stream(adev->dm.dc, stream);
|
||||
|
||||
if (dc_result == DC_OK &&
|
||||
stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
|
||||
dc_result = dm_dp_mst_is_port_support_mode(aconnector, stream);
|
||||
|
||||
if (dc_result == DC_OK)
|
||||
dc_result = dm_validate_stream_and_context(adev->dm.dc, stream);
|
||||
|
||||
if (dc_result == DC_OK)
|
||||
dc_result = dm_validate_stream_color_format(drm_state, stream);
|
||||
|
||||
if (dc_result == DC_OK)
|
||||
return stream;
|
||||
|
||||
drm_dbg_kms(connector->dev, "Pruned mode %d x %d (refresh rate %d) %s %s -- %s\n",
|
||||
drm_mode->hdisplay,
|
||||
drm_mode->vdisplay,
|
||||
drm_mode->clock,
|
||||
drm_mode_vrefresh(drm_mode),
|
||||
dc_pixel_encoding_to_str(stream->timing.pixel_encoding),
|
||||
dc_color_depth_to_str(stream->timing.display_color_depth),
|
||||
dc_status_to_str(dc_result));
|
||||
|
||||
dc_stream_release(stream);
|
||||
stream = NULL;
|
||||
requested_bpc -= 2; /* lower bpc to retry validation */
|
||||
}
|
||||
|
||||
} while (stream == NULL && requested_bpc >= bpc_limit);
|
||||
|
||||
switch (dc_result) {
|
||||
/*
|
||||
* If we failed to validate DP bandwidth stream with the requested RGB color depth,
|
||||
* we try to fallback and configure in order:
|
||||
* YUV422 (8bpc, 6bpc)
|
||||
* YUV420 (8bpc, 6bpc)
|
||||
*/
|
||||
case DC_FAIL_ENC_VALIDATE:
|
||||
case DC_EXCEED_DONGLE_CAP:
|
||||
case DC_NO_DP_LINK_BANDWIDTH:
|
||||
/* recursively entered twice and already tried both YUV422 and YUV420 */
|
||||
if (aconnector->force_yuv422_output && aconnector->force_yuv420_output)
|
||||
break;
|
||||
/* first failure; try YUV422 */
|
||||
if (!aconnector->force_yuv422_output) {
|
||||
drm_dbg_kms(connector->dev, "%s:%d Validation failed with %d, retrying w/ YUV422\n",
|
||||
__func__, __LINE__, dc_result);
|
||||
aconnector->force_yuv422_output = true;
|
||||
/* recursively entered and YUV422 failed, try YUV420 */
|
||||
} else if (!aconnector->force_yuv420_output) {
|
||||
drm_dbg_kms(connector->dev, "%s:%d Validation failed with %d, retrying w/ YUV420\n",
|
||||
__func__, __LINE__, dc_result);
|
||||
aconnector->force_yuv420_output = true;
|
||||
}
|
||||
stream = amdgpu_dm_create_validate_stream_for_sink(connector, drm_mode,
|
||||
dm_state, old_stream);
|
||||
aconnector->force_yuv422_output = false;
|
||||
aconnector->force_yuv420_output = false;
|
||||
break;
|
||||
case DC_OK:
|
||||
break;
|
||||
default:
|
||||
drm_dbg_kms(connector->dev, "%s:%d Unhandled validation failure %d\n",
|
||||
__func__, __LINE__, dc_result);
|
||||
break;
|
||||
}
|
||||
|
||||
return stream;
|
||||
/*
|
||||
* Every sink-supported combination was exhausted without validating;
|
||||
* the mode is genuinely unsupported on this link.
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_create_validate_stream_for_sink);
|
||||
|
||||
@@ -3068,7 +3153,7 @@ static void hdmi_frl_status_polling_work(struct work_struct *work)
|
||||
if (!dc_is_hdmi_signal(dc_link->connector_signal))
|
||||
continue;
|
||||
|
||||
if (dc_link->connector_signal != SIGNAL_TYPE_HDMI_FRL)
|
||||
if (dc_link->frl_link_settings.frl_link_rate == 0)
|
||||
continue;
|
||||
|
||||
link_update = dc_link_frl_poll_status_flag(dc_link);
|
||||
|
||||
@@ -189,13 +189,17 @@ void fill_stream_properties_from_drm_display_mode(
|
||||
const struct drm_connector *connector,
|
||||
const struct drm_connector_state *connector_state,
|
||||
const struct dc_stream_state *old_stream,
|
||||
int requested_bpc);
|
||||
int requested_bpc,
|
||||
enum dc_pixel_encoding requested_encoding,
|
||||
bool is_hdmi_ep);
|
||||
struct dc_stream_state *
|
||||
create_stream_for_sink(struct drm_connector *connector,
|
||||
const struct drm_display_mode *drm_mode,
|
||||
const struct dm_connector_state *dm_state,
|
||||
const struct dc_stream_state *old_stream,
|
||||
int requested_bpc);
|
||||
int requested_bpc,
|
||||
enum dc_pixel_encoding requested_encoding,
|
||||
bool is_hdmi_ep);
|
||||
enum drm_connector_status
|
||||
amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force);
|
||||
enum drm_connector_status
|
||||
|
||||
@@ -604,10 +604,15 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
|
||||
|
||||
/* Enable or disable CRTC CRC generation */
|
||||
if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) {
|
||||
if (!dc_stream_configure_crc(stream_state->ctx->dc,
|
||||
stream_state, NULL, enable, enable, 0, true, crc_poly_mode)) {
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_CRC_WINDOW_NUM; i++) {
|
||||
if (!dc_stream_configure_crc(stream_state->ctx->dc,
|
||||
stream_state, NULL, enable, enable,
|
||||
i, true, crc_poly_mode)) {
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ void amdgpu_dm_crtc_handle_vblank(struct amdgpu_crtc *acrtc)
|
||||
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_crtc_handle_vblank);
|
||||
|
||||
bool amdgpu_dm_crtc_modeset_required(struct drm_crtc_state *crtc_state,
|
||||
struct dc_stream_state *new_stream,
|
||||
@@ -124,7 +125,11 @@ void amdgpu_dm_crtc_set_static_screen_optimze(
|
||||
struct dc_link *link = stream->link;
|
||||
bool set_vsync_event = !sso_enable;
|
||||
|
||||
if (!allow_sr_entry)
|
||||
/*
|
||||
* allow_sr_entry gates only entry. A disable request must still set
|
||||
* the vsync events to force Replay and PSR1 out and keep them blocked.
|
||||
*/
|
||||
if (sso_enable && !allow_sr_entry)
|
||||
return;
|
||||
|
||||
amdgpu_dm_replay_set_event(dm, stream,
|
||||
@@ -134,6 +139,7 @@ void amdgpu_dm_crtc_set_static_screen_optimze(
|
||||
amdgpu_dm_psr_set_event(dm, stream,
|
||||
set_vsync_event, psr_event_vsync, set_vsync_event);
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_crtc_set_static_screen_optimze);
|
||||
|
||||
bool amdgpu_dm_is_headless(struct amdgpu_device *adev)
|
||||
{
|
||||
@@ -163,7 +169,7 @@ bool amdgpu_dm_is_headless(struct amdgpu_device *adev)
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_is_headless);
|
||||
|
||||
static void amdgpu_dm_idle_worker(struct work_struct *work)
|
||||
STATIC_IFN_KUNIT void amdgpu_dm_idle_worker(struct work_struct *work)
|
||||
{
|
||||
struct idle_workqueue *idle_work;
|
||||
|
||||
@@ -197,6 +203,7 @@ static void amdgpu_dm_idle_worker(struct work_struct *work)
|
||||
}
|
||||
idle_work->dm->idle_workqueue->running = false;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_idle_worker);
|
||||
|
||||
struct idle_workqueue *idle_create_workqueue(struct amdgpu_device *adev)
|
||||
{
|
||||
@@ -215,7 +222,7 @@ struct idle_workqueue *idle_create_workqueue(struct amdgpu_device *adev)
|
||||
}
|
||||
EXPORT_IF_KUNIT(idle_create_workqueue);
|
||||
|
||||
static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work)
|
||||
STATIC_IFN_KUNIT void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work)
|
||||
{
|
||||
struct vblank_control_work *vblank_work =
|
||||
container_of(work, struct vblank_control_work, work);
|
||||
@@ -240,6 +247,7 @@ static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work)
|
||||
|
||||
kfree(vblank_work);
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_crtc_vblank_control_worker);
|
||||
|
||||
static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable)
|
||||
{
|
||||
@@ -393,13 +401,15 @@ int amdgpu_dm_crtc_enable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
return amdgpu_dm_crtc_set_vblank(crtc, true);
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_crtc_enable_vblank);
|
||||
|
||||
void amdgpu_dm_crtc_disable_vblank(struct drm_crtc *crtc)
|
||||
{
|
||||
amdgpu_dm_crtc_set_vblank(crtc, false);
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_crtc_disable_vblank);
|
||||
|
||||
static void amdgpu_dm_crtc_destroy_state(struct drm_crtc *crtc,
|
||||
STATIC_IFN_KUNIT void amdgpu_dm_crtc_destroy_state(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state)
|
||||
{
|
||||
struct dm_crtc_state *cur = to_dm_crtc_state(state);
|
||||
@@ -414,8 +424,9 @@ static void amdgpu_dm_crtc_destroy_state(struct drm_crtc *crtc,
|
||||
|
||||
kfree(state);
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_crtc_destroy_state);
|
||||
|
||||
static struct drm_crtc_state *amdgpu_dm_crtc_duplicate_state(struct drm_crtc *crtc)
|
||||
STATIC_IFN_KUNIT struct drm_crtc_state *amdgpu_dm_crtc_duplicate_state(struct drm_crtc *crtc)
|
||||
{
|
||||
struct dm_crtc_state *state, *cur;
|
||||
|
||||
@@ -450,6 +461,7 @@ static struct drm_crtc_state *amdgpu_dm_crtc_duplicate_state(struct drm_crtc *cr
|
||||
|
||||
return &state->base;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_crtc_duplicate_state);
|
||||
|
||||
static void amdgpu_dm_crtc_destroy(struct drm_crtc *crtc)
|
||||
{
|
||||
@@ -463,7 +475,7 @@ static void amdgpu_dm_crtc_destroy(struct drm_crtc *crtc)
|
||||
kfree(crtc);
|
||||
}
|
||||
|
||||
static void amdgpu_dm_crtc_reset_state(struct drm_crtc *crtc)
|
||||
STATIC_IFN_KUNIT void amdgpu_dm_crtc_reset_state(struct drm_crtc *crtc)
|
||||
{
|
||||
struct dm_crtc_state *state;
|
||||
|
||||
@@ -476,6 +488,7 @@ static void amdgpu_dm_crtc_reset_state(struct drm_crtc *crtc)
|
||||
|
||||
__drm_atomic_helper_crtc_reset(crtc, &state->base);
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_crtc_reset_state);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static int amdgpu_dm_crtc_late_register(struct drm_crtc *crtc)
|
||||
@@ -578,7 +591,7 @@ static void amdgpu_dm_crtc_helper_disable(struct drm_crtc *crtc)
|
||||
{
|
||||
}
|
||||
|
||||
static int amdgpu_dm_crtc_count_crtc_active_planes(struct drm_crtc_state *new_crtc_state)
|
||||
STATIC_IFN_KUNIT int amdgpu_dm_crtc_count_crtc_active_planes(struct drm_crtc_state *new_crtc_state)
|
||||
{
|
||||
struct drm_atomic_commit *state = new_crtc_state->state;
|
||||
struct drm_plane *plane;
|
||||
@@ -609,8 +622,9 @@ static int amdgpu_dm_crtc_count_crtc_active_planes(struct drm_crtc_state *new_cr
|
||||
|
||||
return num_active;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_crtc_count_crtc_active_planes);
|
||||
|
||||
static void amdgpu_dm_crtc_update_crtc_active_planes(struct drm_crtc *crtc,
|
||||
STATIC_IFN_KUNIT void amdgpu_dm_crtc_update_crtc_active_planes(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *new_crtc_state)
|
||||
{
|
||||
struct dm_crtc_state *dm_new_crtc_state =
|
||||
@@ -624,6 +638,7 @@ static void amdgpu_dm_crtc_update_crtc_active_planes(struct drm_crtc *crtc,
|
||||
dm_new_crtc_state->active_planes =
|
||||
amdgpu_dm_crtc_count_crtc_active_planes(new_crtc_state);
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_crtc_update_crtc_active_planes);
|
||||
|
||||
STATIC_IFN_KUNIT bool amdgpu_dm_crtc_helper_mode_fixup(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode,
|
||||
|
||||
@@ -46,6 +46,15 @@ bool amdgpu_dm_crtc_vrr_active_irq(struct amdgpu_crtc *acrtc);
|
||||
bool amdgpu_dm_crtc_helper_mode_fixup(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
void amdgpu_dm_crtc_destroy_state(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *state);
|
||||
struct drm_crtc_state *amdgpu_dm_crtc_duplicate_state(struct drm_crtc *crtc);
|
||||
void amdgpu_dm_crtc_reset_state(struct drm_crtc *crtc);
|
||||
int amdgpu_dm_crtc_count_crtc_active_planes(struct drm_crtc_state *new_crtc_state);
|
||||
void amdgpu_dm_crtc_update_crtc_active_planes(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *new_crtc_state);
|
||||
void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work);
|
||||
void amdgpu_dm_idle_worker(struct work_struct *work);
|
||||
#endif
|
||||
|
||||
bool amdgpu_dm_crtc_vrr_active(const struct dm_crtc_state *dm_state);
|
||||
|
||||
@@ -290,15 +290,20 @@ int amdgpu_dm_crtc_get_cursor_mode(struct amdgpu_device *adev,
|
||||
/* Overlay cursor not supported on HW before DCN
|
||||
* DCN401/420 does not have the cursor-on-scaled-plane or cursor-on-yuv-plane restrictions
|
||||
* as previous DCN generations, so enable native mode on DCN401/420
|
||||
*
|
||||
* Always set native cursor mode when the CRTC is disabled,
|
||||
* to make sure it doesn't cause atomic commits to fail when
|
||||
* they are trying to disable the CRTC.
|
||||
*/
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 0, 1) ||
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0) ||
|
||||
#if defined(CONFIG_DRM_AMD_DC_DCN6_0)
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 1) ||
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(6, 0, 0)) {
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(6, 0, 0) ||
|
||||
#else
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 1)) {
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 1) ||
|
||||
#endif
|
||||
!dm_crtc_state->base.enable) {
|
||||
*cursor_mode = DM_CURSOR_NATIVE_MODE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3199,57 +3199,42 @@ static const struct {
|
||||
};
|
||||
|
||||
/*
|
||||
* Force YUV420 output if available from the given mode
|
||||
* Force a specific pixel encoding for the given connector, overriding the
|
||||
* encoding that stream validation would otherwise pick. The value is an
|
||||
* enum dc_pixel_encoding:
|
||||
*
|
||||
* 0 - PIXEL_ENCODING_UNDEFINED (no override, default)
|
||||
* 1 - PIXEL_ENCODING_RGB
|
||||
* 2 - PIXEL_ENCODING_YCBCR422
|
||||
* 3 - PIXEL_ENCODING_YCBCR444
|
||||
* 4 - PIXEL_ENCODING_YCBCR420
|
||||
*/
|
||||
static int force_yuv420_output_set(void *data, u64 val)
|
||||
static int force_yuv_pixel_format_set(void *data, u64 val)
|
||||
{
|
||||
struct amdgpu_dm_connector *connector = data;
|
||||
|
||||
connector->force_yuv420_output = (bool)val;
|
||||
connector->force_yuv_pixel_format = PIXEL_ENCODING_YCBCR420;
|
||||
if (val >= PIXEL_ENCODING_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
connector->force_yuv_pixel_format = (uint8_t)val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if YUV420 is forced when available from the given mode
|
||||
* Read back the pixel encoding currently forced on the given connector.
|
||||
*/
|
||||
static int force_yuv420_output_get(void *data, u64 *val)
|
||||
static int force_yuv_pixel_format_get(void *data, u64 *val)
|
||||
{
|
||||
struct amdgpu_dm_connector *connector = data;
|
||||
|
||||
*val = connector->force_yuv420_output;
|
||||
*val = connector->force_yuv_pixel_format;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(force_yuv420_output_fops, force_yuv420_output_get,
|
||||
force_yuv420_output_set, "%llu\n");
|
||||
|
||||
static int force_yuv422_output_set(void *data, u64 val)
|
||||
{
|
||||
struct amdgpu_dm_connector *connector = data;
|
||||
|
||||
connector->force_yuv422_output = (bool)val;
|
||||
connector->force_yuv_pixel_format = PIXEL_ENCODING_YCBCR422;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(force_yuv422_output_fops, NULL,
|
||||
force_yuv422_output_set, "%llu\n");
|
||||
|
||||
static int force_yuv444_output_set(void *data, u64 val)
|
||||
{
|
||||
struct amdgpu_dm_connector *connector = data;
|
||||
|
||||
connector->force_yuv_pixel_format = PIXEL_ENCODING_YCBCR444;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(force_yuv444_output_fops, NULL,
|
||||
force_yuv444_output_set, "%llu\n");
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(force_yuv_pixel_format_fops, force_yuv_pixel_format_get,
|
||||
force_yuv_pixel_format_set, "%llu\n");
|
||||
|
||||
/*
|
||||
* Read Replay state
|
||||
@@ -3699,9 +3684,7 @@ static const struct {
|
||||
char *name;
|
||||
const struct file_operations *fops;
|
||||
} connector_debugfs_entries[] = {
|
||||
{"force_yuv420_output", &force_yuv420_output_fops},
|
||||
{"force_yuv422_output", &force_yuv422_output_fops},
|
||||
{"force_yuv444_output", &force_yuv444_output_fops},
|
||||
{"force_yuv_pixel_format", &force_yuv_pixel_format_fops},
|
||||
{"trigger_hotplug", &trigger_hotplug_debugfs_fops},
|
||||
{"internal_display", &internal_display_fops},
|
||||
{"odm_combine_segments", &odm_combine_segments_fops}
|
||||
|
||||
@@ -63,6 +63,7 @@ MODULE_FIRMWARE(FIRMWARE_DCN_36_DMUB);
|
||||
MODULE_FIRMWARE(FIRMWARE_DCN_401_DMUB);
|
||||
MODULE_FIRMWARE(FIRMWARE_DCN_42_DMUB);
|
||||
MODULE_FIRMWARE(FIRMWARE_DCN_42B_DMUB);
|
||||
MODULE_FIRMWARE(FIRMWARE_DCN_60_DMUB);
|
||||
|
||||
/**
|
||||
* dm_dmub_aux_setconfig_callback - Callback for AUX or SET_CONFIG command.
|
||||
@@ -408,6 +409,9 @@ STATIC_IFN_KUNIT void *dm_dmub_get_vbios_bounding_box(struct amdgpu_device *adev
|
||||
case IP_VERSION(4, 2, 1):
|
||||
bb_size = sizeof(struct dml2_soc_bb);
|
||||
break;
|
||||
case IP_VERSION(6, 0, 0):
|
||||
bb_size = sizeof(struct dmub_soc_bb_params);
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@@ -560,6 +564,9 @@ int dm_dmub_sw_init(struct amdgpu_device *adev)
|
||||
case IP_VERSION(4, 2, 1):
|
||||
dmub_asic = DMUB_ASIC_DCN42B;
|
||||
break;
|
||||
case IP_VERSION(6, 0, 0):
|
||||
dmub_asic = DMUB_ASIC_DCN60;
|
||||
break;
|
||||
default:
|
||||
/* ASIC doesn't support DMUB. */
|
||||
return 0;
|
||||
@@ -752,6 +759,9 @@ int dm_init_microcode(struct amdgpu_device *adev)
|
||||
case IP_VERSION(4, 2, 1):
|
||||
fw_name_dmub = FIRMWARE_DCN_42B_DMUB;
|
||||
break;
|
||||
case IP_VERSION(6, 0, 0):
|
||||
fw_name_dmub = FIRMWARE_DCN_60_DMUB;
|
||||
break;
|
||||
default:
|
||||
/* ASIC doesn't support DMUB. */
|
||||
return 0;
|
||||
|
||||
@@ -62,6 +62,7 @@ int dm_init_microcode(struct amdgpu_device *adev);
|
||||
#define FIRMWARE_DCN_401_DMUB "amdgpu/dcn_4_0_1_dmcub.bin"
|
||||
#define FIRMWARE_DCN_42_DMUB "amdgpu/dcn_4_2_dmcub.bin"
|
||||
#define FIRMWARE_DCN_42B_DMUB "amdgpu/dcn_4_2_1_dmcub.bin"
|
||||
#define FIRMWARE_DCN_60_DMUB "amdgpu/dcn_6_0_0_dmcub.bin"
|
||||
#define FIRMWARE_RAVEN_DMCU "amdgpu/raven_dmcu.bin"
|
||||
#define FIRMWARE_NAVI12_DMCU "amdgpu/navi12_dmcu.bin"
|
||||
|
||||
|
||||
@@ -365,7 +365,7 @@ void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_inde
|
||||
|
||||
cancel_delayed_work(&hdcp_w->property_validate_dwork);
|
||||
|
||||
for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) {
|
||||
for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_COUNT; conn_index++) {
|
||||
hdcp_w->encryption_status[conn_index] =
|
||||
MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
|
||||
if (hdcp_w->aconnector[conn_index]) {
|
||||
@@ -418,7 +418,7 @@ void event_property_update(struct work_struct *work)
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_state *conn_state;
|
||||
|
||||
for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX; conn_index++) {
|
||||
for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_COUNT; conn_index++) {
|
||||
aconnector = hdcp_work->aconnector[conn_index];
|
||||
|
||||
if (!aconnector)
|
||||
@@ -478,7 +478,7 @@ void event_property_validate(struct work_struct *work)
|
||||
|
||||
guard(mutex)(&hdcp_work->mutex);
|
||||
|
||||
for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_INDEX;
|
||||
for (conn_index = 0; conn_index < AMDGPU_DM_MAX_DISPLAY_COUNT;
|
||||
conn_index++) {
|
||||
aconnector = hdcp_work->aconnector[conn_index];
|
||||
|
||||
@@ -897,10 +897,10 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev,
|
||||
|
||||
memset(hdcp_work[i].aconnector, 0,
|
||||
sizeof(struct amdgpu_dm_connector *) *
|
||||
AMDGPU_DM_MAX_DISPLAY_INDEX);
|
||||
AMDGPU_DM_MAX_DISPLAY_COUNT);
|
||||
memset(hdcp_work[i].encryption_status, 0,
|
||||
sizeof(enum mod_hdcp_encryption_status) *
|
||||
AMDGPU_DM_MAX_DISPLAY_INDEX);
|
||||
AMDGPU_DM_MAX_DISPLAY_COUNT);
|
||||
}
|
||||
|
||||
cp_psp->funcs.update_stream_config = update_config;
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
* Minimal declarations needed by this header.
|
||||
* Full amdgpu/DM definitions come from amdgpu_dm.h included by each .c file.
|
||||
*/
|
||||
#define AMDGPU_DM_MAX_DISPLAY_INDEX 31
|
||||
#define AMDGPU_DM_MAX_DISPLAY_COUNT 32
|
||||
struct amdgpu_dm_connector;
|
||||
|
||||
struct mod_hdcp;
|
||||
@@ -57,7 +57,7 @@ struct hdcp_workqueue {
|
||||
struct delayed_work callback_dwork;
|
||||
struct delayed_work watchdog_timer_dwork;
|
||||
struct delayed_work property_validate_dwork;
|
||||
struct amdgpu_dm_connector *aconnector[AMDGPU_DM_MAX_DISPLAY_INDEX];
|
||||
struct amdgpu_dm_connector *aconnector[AMDGPU_DM_MAX_DISPLAY_COUNT];
|
||||
struct mutex mutex;
|
||||
|
||||
struct mod_hdcp hdcp;
|
||||
@@ -65,7 +65,7 @@ struct hdcp_workqueue {
|
||||
struct mod_hdcp_display display;
|
||||
struct mod_hdcp_link link;
|
||||
|
||||
enum mod_hdcp_encryption_status encryption_status[AMDGPU_DM_MAX_DISPLAY_INDEX];
|
||||
enum mod_hdcp_encryption_status encryption_status[AMDGPU_DM_MAX_DISPLAY_COUNT];
|
||||
/* when display is unplugged from mst hub, connctor will be
|
||||
* destroyed within dm_dp_mst_connector_destroy. connector
|
||||
* hdcp perperties, like type, undesired, desired, enabled,
|
||||
@@ -75,9 +75,9 @@ struct hdcp_workqueue {
|
||||
* will be retrieved from hdcp_work within dm_dp_mst_get_modes
|
||||
*/
|
||||
/* un-desired, desired, enabled */
|
||||
unsigned int content_protection[AMDGPU_DM_MAX_DISPLAY_INDEX];
|
||||
unsigned int content_protection[AMDGPU_DM_MAX_DISPLAY_COUNT];
|
||||
/* hdcp1.x, hdcp2.x */
|
||||
unsigned int hdcp_content_type[AMDGPU_DM_MAX_DISPLAY_INDEX];
|
||||
unsigned int hdcp_content_type[AMDGPU_DM_MAX_DISPLAY_COUNT];
|
||||
|
||||
uint8_t max_link;
|
||||
|
||||
|
||||
@@ -1903,3 +1903,9 @@ void dm_helpers_mccs_vcp_set(struct dc_context *ctx, struct dc_link *link,
|
||||
}
|
||||
EXPORT_IF_KUNIT(dm_helpers_mccs_vcp_set);
|
||||
|
||||
bool dm_helpers_submit_i2c_over_aux(struct ddc_service *ddc, uint32_t address, uint8_t offset,
|
||||
uint8_t *cmdBuffer, uint32_t len, bool read)
|
||||
{
|
||||
//TODO: Implement this
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -485,7 +485,8 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector)
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
|
||||
if (adev->dm.hdcp_workqueue) {
|
||||
if (adev->dm.hdcp_workqueue &&
|
||||
connector->index < AMDGPU_DM_MAX_DISPLAY_COUNT) {
|
||||
struct hdcp_workqueue *hdcp_work = adev->dm.hdcp_workqueue;
|
||||
struct hdcp_workqueue *hdcp_w =
|
||||
&hdcp_work[aconnector->dc_link->link_index];
|
||||
|
||||
@@ -144,7 +144,8 @@ void amdgpu_dm_plane_fill_blending_from_plane_state(const struct drm_plane_state
|
||||
* other ASICs use an 8-bit field. The DRM plane alpha is
|
||||
* 16-bit, so scale it down to the width the hardware expects.
|
||||
*/
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0))
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0)
|
||||
|| amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(6, 0, 0))
|
||||
*global_alpha_value = plane_state->alpha >> 4;
|
||||
else
|
||||
*global_alpha_value = plane_state->alpha >> 8;
|
||||
@@ -316,6 +317,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_plane_validate_dcc(struct amdgpu_device *adev,
|
||||
return 0;
|
||||
|
||||
if (adev->family != AMDGPU_FAMILY_GC_12_0_0 &&
|
||||
adev->family != AMDGPU_FAMILY_GC_13_0_1 &&
|
||||
format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -1047,6 +1049,8 @@ STATIC_IFN_KUNIT int amdgpu_dm_plane_get_plane_modifiers(struct amdgpu_device *a
|
||||
amdgpu_dm_plane_add_gfx11_modifiers(adev, mods, &size, &capacity);
|
||||
break;
|
||||
case AMDGPU_FAMILY_GC_12_0_0:
|
||||
case AMDGPU_FAMILY_GC_13_0_1:
|
||||
/* GFX13 (DCN6) shares the GFX12 tiling/DCC binary modifier format. */
|
||||
amdgpu_dm_plane_add_gfx12_modifiers(adev, mods, &size, &capacity);
|
||||
break;
|
||||
}
|
||||
@@ -1187,7 +1191,8 @@ int amdgpu_dm_plane_fill_plane_buffer_attributes(struct amdgpu_device *adev,
|
||||
upper_32_bits(chroma_addr);
|
||||
}
|
||||
|
||||
if (adev->family == AMDGPU_FAMILY_GC_12_0_0) {
|
||||
if (adev->family == AMDGPU_FAMILY_GC_12_0_0
|
||||
|| adev->family == AMDGPU_FAMILY_GC_13_0_1) {
|
||||
ret = amdgpu_dm_plane_fill_gfx12_attrs_from_modifiers(adev, afb, format,
|
||||
rotation, plane_size,
|
||||
tiling_info, dcc,
|
||||
|
||||
@@ -35,4 +35,3 @@ obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_crtc_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_services_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_helpers_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_quirks_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_plane_test.o
|
||||
|
||||
@@ -3416,7 +3416,8 @@ static void dm_test_fill_stream_borders_zeroed(struct kunit *test)
|
||||
timing->v_border_bottom = 8;
|
||||
|
||||
fill_stream_properties_from_drm_display_mode(ctx->stream, ctx->mode,
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8);
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->h_border_left, 0);
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->h_border_right, 0);
|
||||
@@ -3437,7 +3438,8 @@ static void dm_test_fill_stream_rgb_defaults(struct kunit *test)
|
||||
struct dc_crtc_timing *timing = &ctx->stream->timing;
|
||||
|
||||
fill_stream_properties_from_drm_display_mode(ctx->stream, ctx->mode,
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8);
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->pixel_encoding, (int)PIXEL_ENCODING_RGB);
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->timing_3d_format,
|
||||
@@ -3463,7 +3465,8 @@ static void dm_test_fill_stream_sync_polarity_positive(struct kunit *test)
|
||||
ctx->mode->flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC;
|
||||
|
||||
fill_stream_properties_from_drm_display_mode(ctx->stream, ctx->mode,
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8);
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->flags.HSYNC_POSITIVE_POLARITY, 1);
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->flags.VSYNC_POSITIVE_POLARITY, 1);
|
||||
@@ -3482,7 +3485,8 @@ static void dm_test_fill_stream_sync_polarity_negative(struct kunit *test)
|
||||
ctx->mode->flags = 0;
|
||||
|
||||
fill_stream_properties_from_drm_display_mode(ctx->stream, ctx->mode,
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8);
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->flags.HSYNC_POSITIVE_POLARITY, 0);
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->flags.VSYNC_POSITIVE_POLARITY, 0);
|
||||
@@ -3511,7 +3515,8 @@ static void dm_test_fill_stream_inherits_old_stream(struct kunit *test)
|
||||
ctx->mode->flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC;
|
||||
|
||||
fill_stream_properties_from_drm_display_mode(ctx->stream, ctx->mode,
|
||||
&ctx->aconnector->base, ctx->conn_state, old_stream, 8);
|
||||
&ctx->aconnector->base, ctx->conn_state, old_stream, 8,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->vic, 16);
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->flags.HSYNC_POSITIVE_POLARITY, 1);
|
||||
@@ -3541,7 +3546,8 @@ static void dm_test_fill_stream_timing_from_crtc(struct kunit *test)
|
||||
ctx->mode->crtc_clock = 148500;
|
||||
|
||||
fill_stream_properties_from_drm_display_mode(ctx->stream, ctx->mode,
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8);
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->h_addressable, 1920);
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->h_total, 2200);
|
||||
@@ -3568,7 +3574,8 @@ static void dm_test_fill_stream_color_depth_requested_bpc(struct kunit *test)
|
||||
ctx->aconnector->base.display_info.bpc = 12;
|
||||
|
||||
fill_stream_properties_from_drm_display_mode(ctx->stream, ctx->mode,
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 10);
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 10,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->display_color_depth,
|
||||
(int)COLOR_DEPTH_101010);
|
||||
@@ -3585,7 +3592,8 @@ static void dm_test_fill_stream_content_type(struct kunit *test)
|
||||
ctx->conn_state->content_type = DRM_MODE_CONTENT_TYPE_GRAPHICS;
|
||||
|
||||
fill_stream_properties_from_drm_display_mode(ctx->stream, ctx->mode,
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8);
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)ctx->stream->content_type,
|
||||
(int)DISPLAY_CONTENT_TYPE_GRAPHICS);
|
||||
@@ -3603,12 +3611,121 @@ static void dm_test_fill_stream_aspect_ratio(struct kunit *test)
|
||||
ctx->mode->picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9;
|
||||
|
||||
fill_stream_properties_from_drm_display_mode(ctx->stream, ctx->mode,
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8);
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->aspect_ratio,
|
||||
(int)ASPECT_RATIO_16_9);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_fill_stream_encoding_from_caller_ycbcr420 - Test caller-selected 420
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* The helper no longer derives the pixel encoding from the display info; it
|
||||
* applies whatever the caller selected. Passing YCbCr420 must be honoured even
|
||||
* though the DisplayPort sink advertises no YCbCr color formats.
|
||||
*/
|
||||
static void dm_test_fill_stream_encoding_from_caller_ycbcr420(struct kunit *test)
|
||||
{
|
||||
struct dm_test_fill_ctx *ctx = dm_test_fill_ctx_alloc(test);
|
||||
struct dc_crtc_timing *timing = &ctx->stream->timing;
|
||||
|
||||
fill_stream_properties_from_drm_display_mode(ctx->stream, ctx->mode,
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8,
|
||||
PIXEL_ENCODING_YCBCR420, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->pixel_encoding,
|
||||
(int)PIXEL_ENCODING_YCBCR420);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_fill_stream_encoding_from_caller_ycbcr422 - Test caller-selected 422
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* A caller-selected YCbCr422 encoding is applied verbatim.
|
||||
*/
|
||||
static void dm_test_fill_stream_encoding_from_caller_ycbcr422(struct kunit *test)
|
||||
{
|
||||
struct dm_test_fill_ctx *ctx = dm_test_fill_ctx_alloc(test);
|
||||
struct dc_crtc_timing *timing = &ctx->stream->timing;
|
||||
|
||||
fill_stream_properties_from_drm_display_mode(ctx->stream, ctx->mode,
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8,
|
||||
PIXEL_ENCODING_YCBCR422, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->pixel_encoding,
|
||||
(int)PIXEL_ENCODING_YCBCR422);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_fill_stream_encoding_from_caller_ycbcr444 - Test caller-selected 444
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* A caller-selected YCbCr444 encoding is applied verbatim.
|
||||
*/
|
||||
static void dm_test_fill_stream_encoding_from_caller_ycbcr444(struct kunit *test)
|
||||
{
|
||||
struct dm_test_fill_ctx *ctx = dm_test_fill_ctx_alloc(test);
|
||||
struct dc_crtc_timing *timing = &ctx->stream->timing;
|
||||
|
||||
fill_stream_properties_from_drm_display_mode(ctx->stream, ctx->mode,
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 8,
|
||||
PIXEL_ENCODING_YCBCR444, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->pixel_encoding,
|
||||
(int)PIXEL_ENCODING_YCBCR444);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_fill_stream_hdmi_ep_clamps_depth - Test HDMI TMDS depth clamp applied
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* With is_hdmi_ep set the colour depth is clamped to what the sink's max TMDS
|
||||
* clock allows: a 10bpc request that exceeds the limit is reduced to 8bpc.
|
||||
*/
|
||||
static void dm_test_fill_stream_hdmi_ep_clamps_depth(struct kunit *test)
|
||||
{
|
||||
struct dm_test_fill_ctx *ctx = dm_test_fill_ctx_alloc(test);
|
||||
struct dc_crtc_timing *timing = &ctx->stream->timing;
|
||||
|
||||
ctx->aconnector->base.display_info.bpc = 10;
|
||||
/* 10bpc RGB needs 185625 KHz, over the sink's 160 MHz TMDS limit. */
|
||||
ctx->aconnector->base.display_info.max_tmds_clock = 160000;
|
||||
ctx->mode->crtc_clock = 148500;
|
||||
|
||||
fill_stream_properties_from_drm_display_mode(ctx->stream, ctx->mode,
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 10,
|
||||
PIXEL_ENCODING_RGB, true);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->display_color_depth,
|
||||
(int)COLOR_DEPTH_888);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_fill_stream_non_hdmi_ep_keeps_depth - Test no TMDS clamp off HDMI
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* With is_hdmi_ep clear the TMDS clamp is skipped, so the same over-limit
|
||||
* 10bpc request is left untouched. The clamp is HDMI-specific.
|
||||
*/
|
||||
static void dm_test_fill_stream_non_hdmi_ep_keeps_depth(struct kunit *test)
|
||||
{
|
||||
struct dm_test_fill_ctx *ctx = dm_test_fill_ctx_alloc(test);
|
||||
struct dc_crtc_timing *timing = &ctx->stream->timing;
|
||||
|
||||
ctx->aconnector->base.display_info.bpc = 10;
|
||||
ctx->aconnector->base.display_info.max_tmds_clock = 160000;
|
||||
ctx->mode->crtc_clock = 148500;
|
||||
|
||||
fill_stream_properties_from_drm_display_mode(ctx->stream, ctx->mode,
|
||||
&ctx->aconnector->base, ctx->conn_state, NULL, 10,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)timing->display_color_depth,
|
||||
(int)COLOR_DEPTH_101010);
|
||||
}
|
||||
|
||||
/* Tests for create_stream_for_sink() */
|
||||
|
||||
/*
|
||||
@@ -3646,7 +3763,7 @@ static struct dm_test_stream_ctx *dm_test_stream_ctx_alloc(struct kunit *test)
|
||||
DRIVER_MODESET);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->drm);
|
||||
|
||||
ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL);
|
||||
ctx->aconnector = drmm_kzalloc(ctx->drm, sizeof(*ctx->aconnector), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
|
||||
KUNIT_ASSERT_EQ(test,
|
||||
drmm_connector_init(ctx->drm, &ctx->aconnector->base,
|
||||
@@ -3687,7 +3804,8 @@ static void dm_test_create_stream_fake_sink_success(struct kunit *test)
|
||||
struct dc_stream_state *stream;
|
||||
|
||||
stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
|
||||
ctx->dm_state, NULL, 8);
|
||||
ctx->dm_state, NULL, 8,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_ASSERT_NOT_NULL(test, stream);
|
||||
dc_stream_release(stream);
|
||||
@@ -3703,7 +3821,8 @@ static void dm_test_create_stream_sets_dm_context(struct kunit *test)
|
||||
struct dc_stream_state *stream;
|
||||
|
||||
stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
|
||||
ctx->dm_state, NULL, 8);
|
||||
ctx->dm_state, NULL, 8,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_ASSERT_NOT_NULL(test, stream);
|
||||
KUNIT_EXPECT_PTR_EQ(test, stream->dm_stream_context, ctx->aconnector);
|
||||
@@ -3720,7 +3839,8 @@ static void dm_test_create_stream_virtual_signal(struct kunit *test)
|
||||
struct dc_stream_state *stream;
|
||||
|
||||
stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
|
||||
ctx->dm_state, NULL, 8);
|
||||
ctx->dm_state, NULL, 8,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_ASSERT_NOT_NULL(test, stream);
|
||||
KUNIT_EXPECT_EQ(test, (int)stream->signal, (int)SIGNAL_TYPE_VIRTUAL);
|
||||
@@ -3739,7 +3859,8 @@ static void dm_test_create_stream_scaling_src(struct kunit *test)
|
||||
struct dc_stream_state *stream;
|
||||
|
||||
stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
|
||||
ctx->dm_state, NULL, 8);
|
||||
ctx->dm_state, NULL, 8,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_ASSERT_NOT_NULL(test, stream);
|
||||
KUNIT_EXPECT_EQ(test, (int)stream->src.width, 1920);
|
||||
@@ -3770,7 +3891,8 @@ static void dm_test_create_stream_existing_sink(struct kunit *test)
|
||||
ctx->aconnector->dc_sink = sink;
|
||||
|
||||
stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode,
|
||||
ctx->dm_state, NULL, 8);
|
||||
ctx->dm_state, NULL, 8,
|
||||
PIXEL_ENCODING_RGB, false);
|
||||
|
||||
KUNIT_ASSERT_NOT_NULL(test, stream);
|
||||
KUNIT_EXPECT_PTR_EQ(test, stream->sink, sink);
|
||||
@@ -3904,7 +4026,7 @@ static void dm_test_poll_dac_load_returns_cached(struct kunit *test)
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm);
|
||||
adev = drm_to_adev(drm);
|
||||
|
||||
aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
|
||||
aconnector = drmm_kzalloc(drm, sizeof(*aconnector), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, aconnector);
|
||||
KUNIT_ASSERT_EQ(test,
|
||||
drmm_connector_init(drm, &aconnector->base,
|
||||
@@ -3951,7 +4073,7 @@ static struct amdgpu_dm_connector *dm_test_reg_connector(struct kunit *test)
|
||||
DRIVER_MODESET);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm);
|
||||
|
||||
aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
|
||||
aconnector = drmm_kzalloc(drm, sizeof(*aconnector), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, aconnector);
|
||||
KUNIT_ASSERT_EQ(test,
|
||||
drmm_connector_init(drm, &aconnector->base,
|
||||
@@ -4406,7 +4528,7 @@ dm_test_modes_ctx_alloc(struct kunit *test, int connector_type)
|
||||
ctx->drm = dm_test_alloc_drm(test);
|
||||
ctx->aconnector = dm_test_add_connector(test, ctx->drm, connector_type);
|
||||
|
||||
ctx->aenc = kunit_kzalloc(test, sizeof(*ctx->aenc), GFP_KERNEL);
|
||||
ctx->aenc = drmm_kzalloc(ctx->drm, sizeof(*ctx->aenc), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx->aenc);
|
||||
KUNIT_ASSERT_EQ(test,
|
||||
drmm_encoder_init(ctx->drm, &ctx->aenc->base, NULL,
|
||||
@@ -5456,6 +5578,11 @@ static struct kunit_case amdgpu_dm_connector_tests[] = {
|
||||
KUNIT_CASE(dm_test_fill_stream_color_depth_requested_bpc),
|
||||
KUNIT_CASE(dm_test_fill_stream_content_type),
|
||||
KUNIT_CASE(dm_test_fill_stream_aspect_ratio),
|
||||
KUNIT_CASE(dm_test_fill_stream_encoding_from_caller_ycbcr420),
|
||||
KUNIT_CASE(dm_test_fill_stream_encoding_from_caller_ycbcr422),
|
||||
KUNIT_CASE(dm_test_fill_stream_encoding_from_caller_ycbcr444),
|
||||
KUNIT_CASE(dm_test_fill_stream_hdmi_ep_clamps_depth),
|
||||
KUNIT_CASE(dm_test_fill_stream_non_hdmi_ep_keeps_depth),
|
||||
/* create_stream_for_sink */
|
||||
KUNIT_CASE(dm_test_create_stream_fake_sink_success),
|
||||
KUNIT_CASE(dm_test_create_stream_sets_dm_context),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "dc.h"
|
||||
#include "core_types.h"
|
||||
#include "clk_mgr.h"
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_mode.h"
|
||||
#include "amdgpu_dm.h"
|
||||
@@ -114,6 +115,34 @@ struct dc_stream_state *dm_kunit_alloc_stream(struct kunit *test,
|
||||
}
|
||||
EXPORT_SYMBOL(dm_kunit_alloc_stream);
|
||||
|
||||
struct dc_state *dm_kunit_alloc_dc_state(struct kunit *test)
|
||||
{
|
||||
struct dc_state *state;
|
||||
|
||||
state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, state);
|
||||
|
||||
return state;
|
||||
}
|
||||
EXPORT_SYMBOL(dm_kunit_alloc_dc_state);
|
||||
|
||||
struct clk_mgr *dm_kunit_alloc_clk_mgr(struct kunit *test)
|
||||
{
|
||||
struct clk_mgr *clk_mgr;
|
||||
struct clk_mgr_funcs *funcs;
|
||||
|
||||
clk_mgr = kunit_kzalloc(test, sizeof(*clk_mgr), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, clk_mgr);
|
||||
|
||||
funcs = kunit_kzalloc(test, sizeof(*funcs), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, funcs);
|
||||
|
||||
clk_mgr->funcs = funcs;
|
||||
|
||||
return clk_mgr;
|
||||
}
|
||||
EXPORT_SYMBOL(dm_kunit_alloc_clk_mgr);
|
||||
|
||||
void dm_kunit_add_stream_to_state(struct kunit *test, struct dc_state *state,
|
||||
unsigned int index, struct dc_link *link)
|
||||
{
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
struct amdgpu_device;
|
||||
struct amdgpu_display_manager;
|
||||
struct amdgpu_dm_connector;
|
||||
struct clk_mgr;
|
||||
struct dc;
|
||||
struct dc_link;
|
||||
struct dc_state;
|
||||
@@ -25,6 +26,8 @@ struct dc_link *dm_kunit_alloc_link(struct kunit *test);
|
||||
struct dc_link *dm_kunit_alloc_link_with_ctx(struct kunit *test);
|
||||
struct amdgpu_display_manager *dm_kunit_alloc_dm(struct kunit *test);
|
||||
struct drm_device *dm_kunit_alloc_drm_with_connector_list(struct kunit *test);
|
||||
struct dc_state *dm_kunit_alloc_dc_state(struct kunit *test);
|
||||
struct clk_mgr *dm_kunit_alloc_clk_mgr(struct kunit *test);
|
||||
struct dc_stream_state *dm_kunit_alloc_stream(struct kunit *test,
|
||||
struct dc_link *link);
|
||||
void dm_kunit_add_stream_to_state(struct kunit *test, struct dc_state *state,
|
||||
|
||||
@@ -86,6 +86,7 @@ bool dal_bios_parser_init_cmd_tbl_helper2(
|
||||
case DCN_VERSION_4_01:
|
||||
case DCN_VERSION_4_2:
|
||||
case DCN_VERSION_4_2B:
|
||||
case DCN_VERSION_6_0:
|
||||
*h = dal_cmd_tbl_helper_dce112_get_table2();
|
||||
return true;
|
||||
|
||||
|
||||
@@ -195,4 +195,13 @@ AMD_DAL_CLK_MGR_DCN42B = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn42b/,$(CLK_MGR_
|
||||
|
||||
AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN42B)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# DCN60
|
||||
###############################################################################
|
||||
CLK_MGR_DCN60 = dcn60_clk_mgr.o dcn60_clk_mgr_smu_msg.o
|
||||
|
||||
AMD_DAL_CLK_MGR_DCN60 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn60/,$(CLK_MGR_DCN60))
|
||||
|
||||
AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN60)
|
||||
endif
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "dcn401/dcn401_clk_mgr.h"
|
||||
#include "dcn42/dcn42_clk_mgr.h"
|
||||
#include "dcn42b/dcn42b_clk_mgr.h"
|
||||
#include "dcn60/dcn60_clk_mgr.h"
|
||||
|
||||
int clk_mgr_helper_get_active_display_cnt(
|
||||
struct dc *dc,
|
||||
@@ -387,6 +388,17 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p
|
||||
return &clk_mgr->base.base;
|
||||
}
|
||||
break;
|
||||
case AMDGPU_FAMILY_GC_13_0_1: {
|
||||
struct clk_mgr_internal *clk_mgr = dcn60_clk_mgr_construct(ctx, dccg);
|
||||
|
||||
if (clk_mgr == NULL) {
|
||||
BREAK_TO_DEBUGGER();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &clk_mgr->base;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DRM_AMD_DC_FP */
|
||||
default:
|
||||
ASSERT(0); /* Unknown Asic */
|
||||
@@ -451,6 +463,9 @@ void dc_destroy_clk_mgr(struct clk_mgr *clk_mgr_base)
|
||||
case AMDGPU_FAMILY_GC_11_5_4:
|
||||
dcn42_clk_mgr_destroy(clk_mgr);
|
||||
break;
|
||||
case AMDGPU_FAMILY_GC_13_0_1:
|
||||
dcn60_clk_mgr_destroy(clk_mgr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -220,6 +220,7 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,
|
||||
bool update_dispclk = false;
|
||||
bool dpp_clock_lowered = false;
|
||||
bool has_active_display;
|
||||
int actual_dtbclk = 0;
|
||||
|
||||
if (dc->work_arounds.skip_clock_update)
|
||||
return;
|
||||
@@ -260,8 +261,9 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,
|
||||
* For dcn42b (no dtbclk hardware), init_clk_states sets dtbclk_en=false and
|
||||
* new_clocks->dtbclk_en should always be false, so this block never executes.
|
||||
*/
|
||||
if (!clk_mgr_base->clks.dtbclk_en && new_clocks->dtbclk_en) {
|
||||
int actual_dtbclk = 0;
|
||||
actual_dtbclk = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dtbclk);
|
||||
|
||||
if (new_clocks->dtbclk_en && actual_dtbclk < 590000) {
|
||||
|
||||
dcn42_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz);
|
||||
dcn42_smu_set_dtbclk(clk_mgr, true);
|
||||
@@ -343,7 +345,6 @@ void dcn42_update_clocks(struct clk_mgr *clk_mgr_base,
|
||||
dcn42_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz);
|
||||
clk_mgr_base->clks.ref_dtbclk_khz = new_clocks->ref_dtbclk_khz;
|
||||
}
|
||||
|
||||
if (dpp_clock_lowered) {
|
||||
// increase per DPP DTO before lowering global dppclk
|
||||
dcn42_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
|
||||
@@ -1051,7 +1052,27 @@ void dcn42_get_smu_clocks(struct clk_mgr_internal *clk_mgr_int)
|
||||
dm_helpers_free_gpu_mem(clk_mgr_base->ctx, DC_MEM_ALLOC_TYPE_GART,
|
||||
smu_dpm_clks.dpm_clks);
|
||||
}
|
||||
void dcn42_request_dtbclk(struct clk_mgr *clk_mgr_base, bool enable)
|
||||
{
|
||||
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
|
||||
|
||||
/*pmfw might turn off dtblck based on allow_dtbstop*/
|
||||
clk_mgr_base->clks.dtbclk_en = false;
|
||||
|
||||
if (enable) {
|
||||
int actual_dtbclk = 0;
|
||||
|
||||
dcn42_smu_set_dtbclk(clk_mgr, true);
|
||||
actual_dtbclk = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dtbclk);
|
||||
if (actual_dtbclk > 590000) {
|
||||
clk_mgr_base->clks.ref_dtbclk_khz = actual_dtbclk;
|
||||
clk_mgr_base->clks.dtbclk_en = true;
|
||||
}
|
||||
} else {
|
||||
clk_mgr_base->clks.dtbclk_en = false;
|
||||
dcn42_smu_set_dtbclk(clk_mgr, false);
|
||||
}
|
||||
}
|
||||
static struct clk_mgr_funcs dcn42_funcs = {
|
||||
.get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
|
||||
.get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
|
||||
@@ -1065,6 +1086,7 @@ static struct clk_mgr_funcs dcn42_funcs = {
|
||||
.get_max_clock_khz = dcn42_get_max_clock_khz,
|
||||
.get_dispclk_from_dentist = dcn42_get_dispclk_from_dentist,
|
||||
.is_smu_present = dcn42_is_smu_present,
|
||||
.request_dtbclk = dcn42_request_dtbclk,
|
||||
.notify_cstate_disable = dcn42_notify_cstate_disable,
|
||||
};
|
||||
|
||||
|
||||
@@ -84,4 +84,5 @@ void dcn42_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr, struct dcn42
|
||||
void dcn42_get_smu_clocks(struct clk_mgr_internal *clk_mgr_int);
|
||||
void dcn42_update_clocks_fpga(struct clk_mgr *clk_mgr, struct dc_state *context, bool safe_to_lower);
|
||||
int dcn42_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base);
|
||||
void dcn42_request_dtbclk(struct clk_mgr *clk_mgr_base, bool enable);
|
||||
#endif //__DCN42_CLK_MGR_H__
|
||||
|
||||
389
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dalsmc.h
Normal file
389
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dalsmc.h
Normal file
@@ -0,0 +1,389 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright 2026 Advanced Micro Devices, Inc.
|
||||
|
||||
#ifndef DALSMC_H
|
||||
#define DALSMC_H
|
||||
|
||||
/**
|
||||
* @file dalsmc.h
|
||||
*
|
||||
* @brief VBIOS and DAL to PMFW Interface
|
||||
*
|
||||
* Clients: VBIOS and DAL
|
||||
* Protocols: dalsmc
|
||||
*
|
||||
* @date 2016 - 2026
|
||||
*/
|
||||
|
||||
/**
|
||||
* @mainpage PMFW-DAL Message Interface
|
||||
*
|
||||
* The protocol uses six registers:
|
||||
*
|
||||
* - MSG_REG — write the message ID (DALSMC_MSG_*) to trigger the transaction
|
||||
* - ARG_REG_0 — input argument Reg0; also carries response data on completion
|
||||
* - ARG_REG_1 — input argument Reg1
|
||||
* - ARG_REG_2 — input argument Reg2
|
||||
* - ARG_REG_3 — input argument Reg3
|
||||
* - RESP_REG — poll until non-zero; value is a DALSMC_Result_* response code
|
||||
*
|
||||
* Programming sequence:
|
||||
* 1. Clear RESP_REG to 0
|
||||
* 2. Write input arguments to ARG_REG_0..3
|
||||
* 3. Write message ID to MSG_REG (triggers PMFW interrupt)
|
||||
* 4. Poll RESP_REG until non-zero — value is the result code
|
||||
* 5. Read response data from ARG_REG_0 (message-specific)
|
||||
*
|
||||
* For payloads too large for the four argument registers, the protocol supports
|
||||
* DRAM table transfers where DAL allocates a DRAM buffer and exchanges bulk data
|
||||
* with PMFW through system memory.
|
||||
*
|
||||
* This documentation contains the subsections:\n\n
|
||||
* @ref ResponseCodes\n
|
||||
* @ref Messages\n
|
||||
* @ref DramTables\n
|
||||
*/
|
||||
|
||||
#define DALSMC_VERSION 0x1
|
||||
|
||||
/** @defgroup ResponseCodes PMFW Response Codes
|
||||
* @{
|
||||
*/
|
||||
// SMU Response Codes:
|
||||
#define DALSMC_Result_OK 0x01
|
||||
#define DALSMC_Result_Failed 0xFF
|
||||
#define DALSMC_Result_UnknownCmd 0xFE
|
||||
#define DALSMC_Result_CmdRejectedPrereq 0xFD
|
||||
#define DALSMC_Result_CmdRejectedBusy 0xFC
|
||||
/** @} */
|
||||
|
||||
/** @defgroup Messages Message definitions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Generic register overlay — four 32-bit C2PMSG argument registers. */
|
||||
typedef struct {
|
||||
uint32_t Reg0;
|
||||
uint32_t Reg1;
|
||||
uint32_t Reg2;
|
||||
uint32_t Reg3;
|
||||
} DALSMC_args_t;
|
||||
|
||||
/**
|
||||
* DALSMC_MSG_TestMessage - Test interface connectivity.
|
||||
*
|
||||
* Echos back the argument value incremented by 1. Use to verify the mailbox
|
||||
* is functional before sending real messages.
|
||||
*
|
||||
* Request: TestValue — arbitrary test integer
|
||||
* Response: Reg0 — TestValue + 1
|
||||
*/
|
||||
#define DALSMC_MSG_TestMessage 0x01
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t TestValue;
|
||||
uint32_t Reserved[3];
|
||||
};
|
||||
DALSMC_args_t Args;
|
||||
} DALSMC_TestMessage_arg_t;
|
||||
|
||||
/**
|
||||
* DALSMC_MSG_GetMsgHeaderVersion - Query the DALSMC header version running on PMFW.
|
||||
*
|
||||
* DAL uses the returned version to determine which messages are supported in
|
||||
* environments that require backwards compatibility.
|
||||
*
|
||||
* Request: (none)
|
||||
* Response: Reg0 — DALSMC_VERSION value compiled into PMFW
|
||||
*/
|
||||
#define DALSMC_MSG_GetMsgHeaderVersion 0x02
|
||||
|
||||
/**
|
||||
* DALSMC_MSG_TransferTableSmu2Dram - Transfer a PMFW table into DRAM.
|
||||
* DALSMC_MSG_TransferTableDram2Smu - Transfer a DRAM buffer into PMFW.
|
||||
*
|
||||
* Both directions use the same argument layout. The DRAM address must be set
|
||||
* beforehand (AddrLow / AddrHigh are the GPU MC address bits [31:0] / [63:32]).
|
||||
*
|
||||
* Smu2Dram supported tables: TABLE_DAL_INIT (DPM clocks + UTM QoS + memory config)
|
||||
* Dram2Smu supported tables: TABLE_SOC_UTM (debug override of UTM QoS parameters)
|
||||
*
|
||||
* Request: TableId — table identifier (TABLE_* defines below)
|
||||
* AddrLow — GPU MC address bits [31:0] of destination/source buffer
|
||||
* AddrHigh — GPU MC address bits [63:32] of destination/source buffer
|
||||
* Response: (none beyond result code)
|
||||
*/
|
||||
#define DALSMC_MSG_TransferTableSmu2Dram 0x03
|
||||
#define DALSMC_MSG_TransferTableDram2Smu 0x04
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t TableId;
|
||||
uint32_t AddrLow;
|
||||
uint32_t AddrHigh;
|
||||
uint32_t Reserved;
|
||||
};
|
||||
DALSMC_args_t Args;
|
||||
} DALSMC_TransferTable_arg_t;
|
||||
|
||||
/**
|
||||
* DALSMC_MSG_SetHardMinByFreq - Set a lower bound frequency constraint on a PPCLK.
|
||||
*
|
||||
* Response does not indicate that the effective clock has already been raised to
|
||||
* meet the minimum requirement; poll DALSMC_MSG_ReturnHardMinStatus for the status
|
||||
* of the request.
|
||||
*
|
||||
* Supported clocks: SOCCLK, DISPCLK, DPPCLK, DCFCLK, DTBCLK.
|
||||
*
|
||||
* Request: FreqKhz[23:0] — target minimum frequency in kHz (0 to ~16.7 GHz)
|
||||
* Ppclk[31:24] — PPCLK_e clock identifier
|
||||
* Response: (none beyond result code)
|
||||
*/
|
||||
#define DALSMC_MSG_SetHardMinByFreq 0x05
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t FreqKhz : 24;
|
||||
uint32_t Ppclk : 8;
|
||||
uint32_t Reserved[3];
|
||||
};
|
||||
DALSMC_args_t Args;
|
||||
} DALSMC_SetHardMinByFreq_arg_t;
|
||||
|
||||
/**
|
||||
* DALSMC_MSG_SetMinDeepSleepDcfclk - Set the minimum DCFCLK frequency in deep sleep.
|
||||
*
|
||||
* Request: MinDcfclkMhz — minimum DCFCLK frequency in MHz during deep sleep
|
||||
* Response: (none beyond result code)
|
||||
*/
|
||||
#define DALSMC_MSG_SetMinDeepSleepDcfclk 0x06
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t MinDcfclkMhz;
|
||||
uint32_t Reserved[3];
|
||||
};
|
||||
DALSMC_args_t Args;
|
||||
} DALSMC_SetMinDeepSleepDcfclk_arg_t;
|
||||
|
||||
/**
|
||||
* DALSMC_MSG_BacoAudioD3PME - Wake the audio block from D3/BACO.
|
||||
*
|
||||
* Triggers PMFW to bring the AZ (audio) block out of its D3 power state.
|
||||
* No arguments or response data; result code indicates success.
|
||||
*/
|
||||
#define DALSMC_MSG_BacoAudioD3PME 0x07
|
||||
|
||||
/**
|
||||
* DALSMC_MSG_ReturnHardMinStatus - Query outstanding hard-min request status.
|
||||
*
|
||||
* Returns a bitmask reporting which PPCLK hard-min requests have been satisfied
|
||||
* by the arbiter. Each bit position corresponds to the matching PPCLK_e value.
|
||||
* A set bit means the arbiter has reached or exceeded the requested minimum.
|
||||
*
|
||||
* Request: (none)
|
||||
* Response: Reg0 — bitmask of satisfied PPCLKs (bit N set ↔ PPCLK_e N is satisfied)
|
||||
*/
|
||||
#define DALSMC_MSG_ReturnHardMinStatus 0x08
|
||||
|
||||
/**
|
||||
* DALSMC_MSG_IndicatePstateStatus - Indicate to PMFW various DMU behaviors required
|
||||
* to support UCLK P-state, for example whether or not DMU needs to modulate refresh
|
||||
* rate to perform UCLK switches.
|
||||
*
|
||||
* Request: WaitResp[0] — DAL requires a synchronous response before proceeding
|
||||
* DrrEnable[1] — DRR (dynamic refresh rate modulation) is active
|
||||
* AltCh[2] — alternate-channel mode is active
|
||||
* AllowUclk[16] — DCN can tolerate UCLK P-state switches
|
||||
* AllowFclk[17] — DCN can tolerate FCLK P-state switches
|
||||
* Response: (none beyond result code)
|
||||
*/
|
||||
#define DALSMC_MSG_IndicatePstateStatus 0x09
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t WaitResp : 1;
|
||||
uint32_t DrrEnable : 1;
|
||||
uint32_t AltCh : 1;
|
||||
uint32_t Reserved : 13;
|
||||
uint32_t AllowUclk : 1;
|
||||
uint32_t AllowFclk : 1;
|
||||
uint32_t Reserved1 : 14;
|
||||
uint32_t Reserved2[3];
|
||||
};
|
||||
DALSMC_args_t Args;
|
||||
} DALSMC_IndicatePstateStatus_arg_t;
|
||||
|
||||
/**
|
||||
* DALSMC_MSG_UpdateUTMQoSRequest - Update the active UTM QoS bandwidth/latency request.
|
||||
*
|
||||
* Passes the current display bandwidth and latency requirements to PMFW so it
|
||||
* can select the appropriate SoC operating point (UCLK/FCLK level) from the
|
||||
* UTM table. Called whenever the display configuration changes.
|
||||
*
|
||||
* The QoS requirement must take effect before PMFW sends its response.
|
||||
*
|
||||
* Request: LatencySopIndex — index into the UTM SOP table that satisfies latency
|
||||
* NominalBandwidthKBps — required nominal (average) bandwidth in KB/s
|
||||
* UrgentBandwidthKBps — required urgent bandwidth in KB/s
|
||||
* LsdmaBandwidthKBps — required LSDMA bandwidth in KB/s
|
||||
* Response: (none beyond result code)
|
||||
*/
|
||||
#define DALSMC_MSG_UpdateUTMQoSRequest 0x0A
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t LatencySopIndex;
|
||||
uint32_t NominalBandwidthKBps;
|
||||
uint32_t UrgentBandwidthKBps;
|
||||
uint32_t LsdmaBandwidthKBps;
|
||||
};
|
||||
DALSMC_args_t Args;
|
||||
} DALSMC_UpdateUTMQoSRequest_arg_t;
|
||||
|
||||
/**
|
||||
* DALSMC_MSG_SetDisplayIdleOptimizations - Notify PMFW of DCN idle-state conditions.
|
||||
*
|
||||
* Indicates which display-side power optimizations are currently safe to apply.
|
||||
* PMFW uses these flags to gate deeper SoC power states such as S0i2.
|
||||
*
|
||||
* Request: DfRequestDisabled[0] — DF (data fabric) requests from DCN are disabled
|
||||
* PhyRefClkOff[1] — PHY reference clock has been gated off
|
||||
* S0i2Rdy[2] — DCN is ready for the system to enter S0i2
|
||||
* Response: (none beyond result code)
|
||||
*/
|
||||
#define DALSMC_MSG_SetDisplayIdleOptimizations 0x0B
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t DfRequestDisabled : 1;
|
||||
uint32_t PhyRefClkOff : 1;
|
||||
uint32_t S0i2Rdy : 1;
|
||||
uint32_t Reserved : 29;
|
||||
uint32_t Reserved1[3];
|
||||
};
|
||||
DALSMC_args_t Args;
|
||||
} DALSMC_SetDisplayIdleOptimizations_arg_t;
|
||||
|
||||
/**
|
||||
* DALSMC_MSG_SetStutterEfficiency - Report DCN stutter efficiency to PMFW.
|
||||
*
|
||||
* Informs PMFW of the current stutter utilisation for base and low-power stutter
|
||||
* modes so PMFW can adjust memory power policy accordingly.
|
||||
*
|
||||
* Base mode — lower enter+exit latency (PHY LP1, no UCIE LP).
|
||||
* Low-power mode — higher enter+exit latency (PHY LP2, UCIE LP1).
|
||||
*
|
||||
* Request: BaseEfficiencyPct[7:0] — stutter efficiency % in base mode
|
||||
* LowPowerEfficiencyPct[15:8] — stutter efficiency % in low-power mode
|
||||
* Response: (none beyond result code)
|
||||
*/
|
||||
#define DALSMC_MSG_SetStutterEfficiency 0x0C
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t BaseEfficiencyPct : 8;
|
||||
uint32_t LowPowerEfficiencyPct : 8;
|
||||
uint32_t Reserved : 16;
|
||||
uint32_t Reserved1[3];
|
||||
};
|
||||
DALSMC_args_t Args;
|
||||
} DALSMC_SetStutterEfficiency_arg_t;
|
||||
|
||||
#define DALSMC_Message_Count 0x0D ///< Total number of messages
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @defgroup DramTables DRAM Tables
|
||||
* @brief Bulk data structures exchanged between DAL and PMFW via system DRAM.
|
||||
*
|
||||
* Used when the payload exceeds the four 32-bit C2PMSG argument registers
|
||||
* (DALSMC_args_t). DAL allocates a DRAM buffer, passes its address through
|
||||
* DALSMC_TransferTable_arg_t, and issues either a
|
||||
* DALSMC_MSG_TransferTableSmu2Dram or DALSMC_MSG_TransferTableDram2Smu message.
|
||||
* @{
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t LoadLevelCount : 4;
|
||||
uint32_t SopCount : 4;
|
||||
uint32_t Reserved : 24;
|
||||
} SocUtmTableHeader_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t UrgentRampPs;
|
||||
uint32_t TripPs;
|
||||
uint32_t MetaTripToMemPs;
|
||||
uint32_t MaxReqLatencyUrgPs;
|
||||
uint32_t AvgReqLatencyUrgPs;
|
||||
uint32_t MaxReqLatencyNonUrgPs;
|
||||
uint32_t AvgReqLatencyNonUrgPs;
|
||||
uint32_t DfResponseTimePs;
|
||||
uint32_t UrgentBandwidthKBps;
|
||||
uint32_t NominalBandwidthKBps;
|
||||
uint32_t LsdmaBandwidthKBps;
|
||||
uint32_t Reserved[1];
|
||||
} SocUtmSopEntry_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t SmuVersion;
|
||||
uint32_t SmuDriverIfVersion;
|
||||
uint32_t Reserved[2];
|
||||
} DalInitHeader_t;
|
||||
|
||||
#define NUM_CLOCK_LEVELS 8
|
||||
typedef struct {
|
||||
uint32_t Clocks[NUM_CLOCK_LEVELS];
|
||||
uint32_t DcMaxClock;
|
||||
uint32_t NumClocks;
|
||||
uint32_t Reserved[2];
|
||||
} DpmClock_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t NumUmcChannels;
|
||||
uint32_t Reserved[3];
|
||||
} MemoryConfig_t;
|
||||
|
||||
/**
|
||||
* TABLE_SOC_UTM - SoC UTM QoS table.
|
||||
*
|
||||
* Provides per-load-level bandwidth and latency bounds used by the display
|
||||
* engine to meet memory access requirements.
|
||||
*
|
||||
* Normal path: embedded in DalInitTable_t, fetched once via
|
||||
* DALSMC_MSG_TransferTableSmu2Dram(TABLE_DAL_INIT).
|
||||
*
|
||||
* Override path (debug only): TABLE_SOC_UTM via
|
||||
* DALSMC_MSG_TransferTableDram2Smu to override custom QoS parameters into PMFW.
|
||||
*/
|
||||
#define TABLE_SOC_UTM 0xC
|
||||
/* TODO: rename back to MAX_UTM_SOP_COUNT once utm_qos_model_types.h conflict is resolved */
|
||||
#define DALSMC_MAX_UTM_SOP_COUNT 16
|
||||
#define MAX_UTM_LOAD_LEVEL_COUNT 16
|
||||
#define UTM_LOAD_LEVEL_INDEX_IDLE 0
|
||||
#define UTM_LOAD_LEVEL_INDEX_ACTIVE_ALTERNATE_PSTATE 1
|
||||
#define UTM_LOAD_LEVEL_INDEX_ACTIVE 2
|
||||
#define UTM_SOP_ENTRIES_OFFSET(LoadLevel, SopIndex) \
|
||||
(sizeof(SocUtmTableHeader_t) \
|
||||
+ ((LoadLevel) * DALSMC_MAX_UTM_SOP_COUNT \
|
||||
+ (SopIndex)) * sizeof(SocUtmSopEntry_t))
|
||||
typedef struct {
|
||||
SocUtmTableHeader_t Header;
|
||||
SocUtmSopEntry_t Sops[MAX_UTM_LOAD_LEVEL_COUNT][DALSMC_MAX_UTM_SOP_COUNT];
|
||||
} SocUtmTable_t;
|
||||
|
||||
/**
|
||||
* TABLE_DAL_INIT - Full TABLE_DAL_INIT payload transferred from SMU to DRAM.
|
||||
*/
|
||||
#define TABLE_DAL_INIT 0xD
|
||||
#define MAX_PPCLK_COUNT 12
|
||||
#define DPM_CLOCK_OFFSET(Ppclk) \
|
||||
(sizeof(DalInitHeader_t) + (Ppclk) * sizeof(DpmClock_t))
|
||||
#define UTM_TABLE_OFFSET \
|
||||
(sizeof(DalInitHeader_t) + MAX_PPCLK_COUNT * sizeof(DpmClock_t))
|
||||
#define MEMORY_CONFIG_OFFSET \
|
||||
(sizeof(DalInitHeader_t) + MAX_PPCLK_COUNT * sizeof(DpmClock_t) \
|
||||
+ sizeof(SocUtmTable_t))
|
||||
typedef struct {
|
||||
DalInitHeader_t Header;
|
||||
DpmClock_t PPClocks[MAX_PPCLK_COUNT];
|
||||
SocUtmTable_t UtmTable;
|
||||
MemoryConfig_t MemoryConfig;
|
||||
} DalInitTable_t;
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* DALSMC_H */
|
||||
1673
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c
Normal file
1673
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.c
Normal file
File diff suppressed because it is too large
Load Diff
150
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.h
Normal file
150
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn60/dcn60_clk_mgr.h
Normal file
@@ -0,0 +1,150 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright 2025 Advanced Micro Devices, Inc.
|
||||
|
||||
#ifndef __DCN60_CLK_MGR_H_
|
||||
#define __DCN60_CLK_MGR_H_
|
||||
|
||||
#ifdef CONFIG_DRM_AMD_DC_FP
|
||||
#include "bounding_boxes/utm_qos_model_types.h"
|
||||
#include "bounding_boxes/utm_qos_model_dchub_v3.h"
|
||||
#endif
|
||||
|
||||
union dcn60_clk_mgr_block_sequence_params {
|
||||
struct {
|
||||
/* inputs */
|
||||
uint32_t ppclk;
|
||||
uint16_t freq_mhz;
|
||||
/* outputs */
|
||||
int *response;
|
||||
} update_hardmin_params;
|
||||
struct {
|
||||
/* inputs */
|
||||
uint32_t ppclk;
|
||||
int freq_khz;
|
||||
/* outputs */
|
||||
int *response;
|
||||
} update_hardmin_optimized_params;
|
||||
struct {
|
||||
/* inputs */
|
||||
uint16_t freq_mhz;
|
||||
} update_deep_sleep_dcfclk_params;
|
||||
struct {
|
||||
/* inputs */
|
||||
bool allow_fclk;
|
||||
bool allow_uclk;
|
||||
bool wait_resp;
|
||||
bool drr_enable;
|
||||
bool alt_ch_enable;
|
||||
} indicate_pstate_status_params;
|
||||
struct {
|
||||
/* inputs */
|
||||
struct dc_state *context;
|
||||
int *ref_dppclk_khz;
|
||||
bool safe_to_lower;
|
||||
} update_dppclk_dto_params;
|
||||
struct {
|
||||
/* inputs */
|
||||
struct dc_state *context;
|
||||
int *ref_dtbclk_khz;
|
||||
} update_dtbclk_dto_params;
|
||||
struct {
|
||||
/* inputs */
|
||||
struct dc_state *context;
|
||||
} update_dentist_params;
|
||||
struct {
|
||||
/* inputs */
|
||||
struct dmcu *dmcu;
|
||||
unsigned int wait;
|
||||
} update_psr_wait_loop_params;
|
||||
struct {
|
||||
/* inputs */
|
||||
uint8_t base_efficiency;
|
||||
uint8_t low_power_efficiency;
|
||||
} update_stutter_efficiency_params;
|
||||
struct {
|
||||
unsigned int utm_urgent_bandwidth_lb_KBps;
|
||||
unsigned int utm_nominal_bandwidth_lb_KBps;
|
||||
unsigned int utm_lsdma_bandwidth_lb_KBps;
|
||||
unsigned int utm_latency_ub_index;
|
||||
} update_utm_qos_request_params;
|
||||
};
|
||||
|
||||
enum dcn60_clk_mgr_block_sequence_func {
|
||||
CLK_MGR60_READ_CLOCKS_FROM_DENTIST,
|
||||
CLK_MGR60_UPDATE_HARDMIN_PPCLK,
|
||||
CLK_MGR60_UPDATE_HARDMIN_PPCLK_OPTIMIZED,
|
||||
CLK_MGR60_UPDATE_DEEP_SLEEP_DCFCLK,
|
||||
CLK_MGR60_INDICATE_PSTATE_STATUS,
|
||||
CLK_MGR60_UPDATE_DPPCLK_DTO,
|
||||
CLK_MGR60_UPDATE_DTBCLK_DTO,
|
||||
CLK_MGR60_UPDATE_DENTIST,
|
||||
CLK_MGR60_UPDATE_PSR_WAIT_LOOP,
|
||||
CLK_MGR60_UPDATE_STUTTER_EFFICIENCY,
|
||||
CLK_MGR60_UPDATE_UTM_QOS_REQUEST
|
||||
};
|
||||
|
||||
struct dcn60_clk_mgr_block_sequence {
|
||||
union dcn60_clk_mgr_block_sequence_params params;
|
||||
enum dcn60_clk_mgr_block_sequence_func func;
|
||||
};
|
||||
|
||||
struct dcn60_update_action {
|
||||
/** clk_mgr state needs updating */
|
||||
bool update;
|
||||
/** SMU message required */
|
||||
bool send_message;
|
||||
};
|
||||
|
||||
struct dcn60_enablement_action {
|
||||
/** feature transitioning to enabled */
|
||||
bool enable;
|
||||
/** feature transitioning to disabled */
|
||||
bool disable;
|
||||
/** SMU message required for this transition */
|
||||
bool send_message;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dcn60_bandwidth_clocks_update_action - captures what clock and
|
||||
* p-state changes are needed for a bandwidth update, separating the action
|
||||
* logic from block sequence construction and state mutation.
|
||||
*/
|
||||
struct dcn60_bandwidth_clocks_update_action {
|
||||
struct dcn60_update_action dcfclk;
|
||||
struct dcn60_update_action deep_sleep_dcfclk;
|
||||
struct dcn60_update_action socclk;
|
||||
struct dcn60_update_action stutter;
|
||||
struct dcn60_update_action utm_qos;
|
||||
struct dcn60_enablement_action uclk_pstate;
|
||||
struct dcn60_enablement_action fclk_pstate;
|
||||
struct dcn60_enablement_action fams;
|
||||
struct dcn60_enablement_action alt_ch;
|
||||
};
|
||||
|
||||
struct dcn60_clk_mgr {
|
||||
struct clk_mgr_internal base;
|
||||
struct dcn60_clk_mgr_block_sequence block_sequence[DCN401_CLK_MGR_MAX_SEQUENCE_SIZE];
|
||||
#ifdef CONFIG_DRM_AMD_DC_FP
|
||||
struct utm_qos_model utm_qos_model;
|
||||
struct utm_qos_model_dchub_v3 dchub_v3;
|
||||
#endif
|
||||
unsigned int num_block_sequence_steps;
|
||||
};
|
||||
|
||||
void dcn60_init_clocks(struct clk_mgr *clk_mgr_base);
|
||||
|
||||
struct block_sequence_state;
|
||||
|
||||
void dcn60_build_clock_update_for_bls(
|
||||
struct clk_mgr *clk_mgr_base,
|
||||
struct dc_state *context,
|
||||
bool safe_to_lower,
|
||||
struct block_sequence_state *seq_state);
|
||||
|
||||
struct clk_mgr_internal *dcn60_clk_mgr_construct(struct dc_context *ctx,
|
||||
struct dccg *dccg);
|
||||
|
||||
void dcn60_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr);
|
||||
|
||||
#endif /* __DCN60_CLK_MGR_H_ */
|
||||
@@ -0,0 +1,369 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright 2025 Advanced Micro Devices, Inc.
|
||||
|
||||
#include "dcn60_clk_mgr_smu_msg.h"
|
||||
|
||||
#include "clk_mgr_internal.h"
|
||||
#include "reg_helper.h"
|
||||
|
||||
#include "dalsmc.h"
|
||||
#include "dcn401/dcn401_smu14_driver_if.h"
|
||||
|
||||
/* MMIO = MP1_BASE__INST0_SEG1 (0x16200 from at2_offset.h)
|
||||
* + regMP1_SMN_C2PMSG_N (sequential from 0xA2)
|
||||
* MSG=C2PMSG_98, RESP=C2PMSG_99, ARG0..3=C2PMSG_100..103
|
||||
*/
|
||||
#ifndef mmDAL_MSG_REG
|
||||
#define mmDAL_MSG_REG 0x162A2
|
||||
#endif
|
||||
#ifndef mmDAL_RESP_REG
|
||||
#define mmDAL_RESP_REG 0x162A3
|
||||
#endif
|
||||
#ifndef mmDAL_ARG_REG
|
||||
#define mmDAL_ARG_REG 0x162A4
|
||||
#endif
|
||||
#ifndef mmDAL_ARG_REG_0
|
||||
#define mmDAL_ARG_REG_0 0x162A4
|
||||
#endif
|
||||
#ifndef mmDAL_ARG_REG_1
|
||||
#define mmDAL_ARG_REG_1 0x162A5
|
||||
#endif
|
||||
#ifndef mmDAL_ARG_REG_2
|
||||
#define mmDAL_ARG_REG_2 0x162A6
|
||||
#endif
|
||||
#ifndef mmDAL_ARG_REG_3
|
||||
#define mmDAL_ARG_REG_3 0x162A7
|
||||
#endif
|
||||
|
||||
#define REG(reg_name) \
|
||||
mm ## reg_name
|
||||
|
||||
#include "logger_types.h"
|
||||
|
||||
|
||||
#define smu_print(str, ...) {DC_LOG_SMU(str, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
* dcn60_smu_wait_for_response - Poll DAL_RESP_REG until non-zero.
|
||||
* @clk_mgr: clock manager instance
|
||||
* @delay_us: microseconds to wait between each poll iteration
|
||||
* @max_retries: maximum number of poll iterations before giving up
|
||||
* @total_delay_us: if non-NULL, accumulates the total poll delay
|
||||
*
|
||||
* Cannot use REG_WAIT because the condition is "not equal to zero"
|
||||
* and the translation in msg_if.h is incompatible with REG_WAIT.
|
||||
*
|
||||
* Return: RESP_REG value (non-zero on success, 0 on timeout)
|
||||
*/
|
||||
static uint32_t dcn60_smu_wait_for_response(struct clk_mgr_internal *clk_mgr,
|
||||
unsigned int delay_us, unsigned int max_retries,
|
||||
unsigned int *total_delay_us)
|
||||
{
|
||||
uint32_t reg = 0;
|
||||
|
||||
if (total_delay_us)
|
||||
*total_delay_us = 0;
|
||||
|
||||
do {
|
||||
reg = REG_READ(DAL_RESP_REG);
|
||||
if (reg)
|
||||
break;
|
||||
|
||||
if (delay_us >= 1000)
|
||||
msleep(delay_us/1000);
|
||||
else if (delay_us > 0)
|
||||
udelay(delay_us);
|
||||
if (total_delay_us)
|
||||
*total_delay_us += delay_us;
|
||||
} while (max_retries--);
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
/**
|
||||
* dcn60_smu_send_msg_with_args - Send a DALSMC message with four argument registers.
|
||||
* @clk_mgr: clock manager instance
|
||||
* @msg_id: DALSMC_MSG_* message identifier
|
||||
* @args: four-register argument payload
|
||||
* @param_out: if non-NULL, receives ARG_REG_0 on success
|
||||
* @total_delay_us: if non-NULL, accumulates the total poll delay
|
||||
*/
|
||||
static bool dcn60_smu_send_msg_with_args(struct clk_mgr_internal *clk_mgr,
|
||||
uint32_t msg_id, DALSMC_args_t args, uint32_t *param_out,
|
||||
unsigned int *total_delay_us)
|
||||
{
|
||||
unsigned int delay1_us = 0, delay2_us = 0;
|
||||
|
||||
if (total_delay_us)
|
||||
*total_delay_us = 0;
|
||||
|
||||
/* Wait for response register to be ready */
|
||||
dcn60_smu_wait_for_response(clk_mgr, 10, 200000,
|
||||
total_delay_us ? &delay1_us : NULL);
|
||||
|
||||
smu_print("SMU msg 0x%x enter: arg0=0x%08x arg1=0x%08x arg2=0x%08x arg3=0x%08x\n",
|
||||
msg_id, args.Reg0, args.Reg1, args.Reg2, args.Reg3);
|
||||
TRACE_SMU_MSG_ENTER(msg_id, args.Reg0, clk_mgr->base.ctx);
|
||||
|
||||
/* Clear response register */
|
||||
REG_WRITE(DAL_RESP_REG, 0);
|
||||
|
||||
/* Write all four argument registers */
|
||||
REG_WRITE(DAL_ARG_REG_0, args.Reg0);
|
||||
REG_WRITE(DAL_ARG_REG_1, args.Reg1);
|
||||
REG_WRITE(DAL_ARG_REG_2, args.Reg2);
|
||||
REG_WRITE(DAL_ARG_REG_3, args.Reg3);
|
||||
|
||||
/* Trigger the message transaction by writing the message ID */
|
||||
REG_WRITE(DAL_MSG_REG, msg_id);
|
||||
|
||||
/* Wait for response */
|
||||
if (dcn60_smu_wait_for_response(clk_mgr, 10, 200000,
|
||||
total_delay_us ? &delay2_us : NULL) == DALSMC_Result_OK) {
|
||||
if (param_out)
|
||||
*param_out = REG_READ(DAL_ARG_REG_0);
|
||||
|
||||
if (total_delay_us)
|
||||
*total_delay_us = delay1_us + delay2_us;
|
||||
|
||||
smu_print("SMU msg 0x%x exit: ok resp=0x%08x\n",
|
||||
msg_id, param_out ? *param_out : 0);
|
||||
TRACE_SMU_MSG_EXIT(true, param_out ? *param_out : 0, clk_mgr->base.ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (total_delay_us)
|
||||
*total_delay_us = delay1_us + 2000000;
|
||||
|
||||
smu_print("SMU msg 0x%x exit: failed\n", msg_id);
|
||||
TRACE_SMU_MSG_EXIT(false, 0, clk_mgr->base.ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int dcn60_smu_get_hard_min_status(struct clk_mgr_internal *clk_mgr,
|
||||
bool *no_timeout, unsigned int *total_delay_us)
|
||||
{
|
||||
DALSMC_args_t args = {};
|
||||
uint32_t response = 0;
|
||||
|
||||
*no_timeout = dcn60_smu_send_msg_with_args(clk_mgr,
|
||||
DALSMC_MSG_ReturnHardMinStatus, args, &response,
|
||||
total_delay_us);
|
||||
|
||||
smu_print("SMU Get hard min status: no_timeout %d delay %d us clk bits %x\n",
|
||||
*no_timeout, *total_delay_us, response);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
static bool dcn60_smu_wait_hard_min_status(struct clk_mgr_internal *clk_mgr, uint32_t ppclk)
|
||||
{
|
||||
const unsigned int max_delay_us = 1000000;
|
||||
|
||||
unsigned int hardmin_status_mask = (1 << ppclk);
|
||||
unsigned int total_delay_us = 0;
|
||||
bool hardmin_done = false;
|
||||
|
||||
while (!hardmin_done && total_delay_us < max_delay_us) {
|
||||
unsigned int hardmin_status;
|
||||
unsigned int read_total_delay_us;
|
||||
bool no_timeout;
|
||||
|
||||
if (!hardmin_done && total_delay_us > 0) {
|
||||
/* hardmin not yet fulfilled, wait 500us and retry*/
|
||||
udelay(500);
|
||||
total_delay_us += 500;
|
||||
|
||||
smu_print("SMU Wait hard min status for %d us\n", total_delay_us);
|
||||
}
|
||||
|
||||
hardmin_status = dcn60_smu_get_hard_min_status(clk_mgr, &no_timeout, &read_total_delay_us);
|
||||
total_delay_us += read_total_delay_us;
|
||||
hardmin_done = hardmin_status & hardmin_status_mask;
|
||||
}
|
||||
|
||||
return hardmin_done;
|
||||
}
|
||||
|
||||
/* TODO: update callers to pass kHz directly for finer granularity
|
||||
* now that the DALSMC interface supports 24-bit kHz encoding.
|
||||
*/
|
||||
unsigned int dcn60_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint16_t freq_mhz)
|
||||
{
|
||||
DALSMC_SetHardMinByFreq_arg_t arg = {};
|
||||
uint32_t response = 0;
|
||||
bool hard_min_done = false;
|
||||
|
||||
smu_print("SMU Set hard min by freq: clk = %d, freq_mhz = %d MHz\n", clk, freq_mhz);
|
||||
|
||||
/* New interface encodes frequency in kHz (24-bit) and PPCLK in bits [31:24] */
|
||||
arg.FreqKhz = (uint32_t)freq_mhz * 1000;
|
||||
arg.Ppclk = clk;
|
||||
|
||||
dcn60_smu_send_msg_with_args(clk_mgr,
|
||||
DALSMC_MSG_SetHardMinByFreq, arg.Args, &response, NULL);
|
||||
|
||||
/* wait until hardmin acknowledged */
|
||||
hard_min_done = dcn60_smu_wait_hard_min_status(clk_mgr, clk);
|
||||
smu_print("SMU Frequency set = %d KHz hard_min_done %d\n", response, hard_min_done);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
void dcn60_smu_set_stutter_efficiency(struct clk_mgr_internal *clk_mgr, uint8_t base_efficiency, uint8_t low_power_efficiency)
|
||||
{
|
||||
DALSMC_SetStutterEfficiency_arg_t arg = {};
|
||||
|
||||
smu_print("SMU Set stutter efficiencies: base(LP1) = %d percent, low power(LP2) = %d percent\n",
|
||||
base_efficiency, low_power_efficiency);
|
||||
|
||||
arg.BaseEfficiencyPct = base_efficiency;
|
||||
arg.LowPowerEfficiencyPct = low_power_efficiency;
|
||||
|
||||
dcn60_smu_send_msg_with_args(clk_mgr,
|
||||
DALSMC_MSG_SetStutterEfficiency, arg.Args, NULL, NULL);
|
||||
}
|
||||
|
||||
void dcn60_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, uint32_t freq_mhz)
|
||||
{
|
||||
DALSMC_SetMinDeepSleepDcfclk_arg_t arg = {};
|
||||
|
||||
smu_print("SMU Set min deep sleep dcfclk: freq_mhz = %d MHz\n", freq_mhz);
|
||||
|
||||
arg.MinDcfclkMhz = freq_mhz;
|
||||
|
||||
dcn60_smu_send_msg_with_args(clk_mgr,
|
||||
DALSMC_MSG_SetMinDeepSleepDcfclk, arg.Args, NULL, NULL);
|
||||
}
|
||||
|
||||
void dcn60_smu_set_pme_workaround(struct clk_mgr_internal *clk_mgr)
|
||||
{
|
||||
DALSMC_args_t args = {};
|
||||
|
||||
smu_print("SMU Set PME workaround (BacoAudioD3PME)\n");
|
||||
|
||||
dcn60_smu_send_msg_with_args(clk_mgr,
|
||||
DALSMC_MSG_BacoAudioD3PME, args, NULL, NULL);
|
||||
}
|
||||
|
||||
void dcn60_smu_indicate_pstate_status(struct clk_mgr_internal *clk_mgr,
|
||||
bool allow_fclk, bool allow_uclk,
|
||||
bool wait_resp, bool drr_enable, bool alt_ch_enable)
|
||||
{
|
||||
DALSMC_IndicatePstateStatus_arg_t arg = {};
|
||||
|
||||
smu_print("SMU Indicate pstate status: allow_fclk=%d allow_uclk=%d wait_resp=%d drr_enable=%d alt_ch_enable=%d\n",
|
||||
allow_fclk, allow_uclk, wait_resp, drr_enable, alt_ch_enable);
|
||||
|
||||
arg.AllowFclk = allow_fclk ? 1 : 0;
|
||||
arg.AllowUclk = allow_uclk ? 1 : 0;
|
||||
arg.WaitResp = wait_resp ? 1 : 0;
|
||||
arg.DrrEnable = drr_enable ? 1 : 0;
|
||||
arg.AltCh = alt_ch_enable ? 1 : 0;
|
||||
|
||||
dcn60_smu_send_msg_with_args(clk_mgr,
|
||||
DALSMC_MSG_IndicatePstateStatus, arg.Args, NULL, NULL);
|
||||
}
|
||||
|
||||
static bool dcn60_smu_transfer_table_smu_2_dram(struct clk_mgr_internal *clk_mgr,
|
||||
uint32_t table_id, long long dram_addr)
|
||||
{
|
||||
DALSMC_TransferTable_arg_t arg = {};
|
||||
|
||||
smu_print("SMU TransferTableSmu2Dram: table_id=0x%x addr=0x%08x_%08x\n",
|
||||
table_id,
|
||||
(uint32_t)(dram_addr >> 32),
|
||||
(uint32_t)(dram_addr & 0xFFFFFFFF));
|
||||
|
||||
arg.TableId = table_id;
|
||||
arg.AddrLow = (uint32_t)(dram_addr & 0xFFFFFFFF);
|
||||
arg.AddrHigh = (uint32_t)(dram_addr >> 32);
|
||||
|
||||
return dcn60_smu_send_msg_with_args(clk_mgr,
|
||||
DALSMC_MSG_TransferTableSmu2Dram, arg.Args, NULL, NULL);
|
||||
}
|
||||
|
||||
static bool dcn60_smu_transfer_table_dram_2_smu(struct clk_mgr_internal *clk_mgr,
|
||||
uint32_t table_id, long long dram_addr)
|
||||
{
|
||||
DALSMC_TransferTable_arg_t arg = {};
|
||||
|
||||
smu_print("SMU TransferTableDram2Smu: table_id=0x%x addr=0x%08x_%08x\n",
|
||||
table_id,
|
||||
(uint32_t)(dram_addr >> 32),
|
||||
(uint32_t)(dram_addr & 0xFFFFFFFF));
|
||||
|
||||
arg.TableId = table_id;
|
||||
arg.AddrLow = (uint32_t)(dram_addr & 0xFFFFFFFF);
|
||||
arg.AddrHigh = (uint32_t)(dram_addr >> 32);
|
||||
|
||||
return dcn60_smu_send_msg_with_args(clk_mgr,
|
||||
DALSMC_MSG_TransferTableDram2Smu, arg.Args, NULL, NULL);
|
||||
}
|
||||
|
||||
bool dcn60_smu_set_soc_utm_table(struct clk_mgr_internal *clk_mgr,
|
||||
long long dram_addr)
|
||||
{
|
||||
return dcn60_smu_transfer_table_dram_2_smu(clk_mgr,
|
||||
TABLE_SOC_UTM, dram_addr);
|
||||
}
|
||||
|
||||
bool dcn60_smu_get_dal_init_table(struct clk_mgr_internal *clk_mgr,
|
||||
const DalInitTable_t **init_table)
|
||||
{
|
||||
if (!dcn60_smu_transfer_table_smu_2_dram(clk_mgr,
|
||||
TABLE_DAL_INIT, clk_mgr->dal_init_table_addr))
|
||||
return false;
|
||||
|
||||
*init_table = (const DalInitTable_t *)clk_mgr->dal_init_table;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dcn60_smu_update_utm_qos_request(struct clk_mgr_internal *clk_mgr,
|
||||
uint32_t latency_sop_index,
|
||||
uint32_t nominal_bandwidth_KBps,
|
||||
uint32_t urgent_bandwidth_KBps,
|
||||
uint32_t lsdma_bandwidth_KBps)
|
||||
{
|
||||
DALSMC_UpdateUTMQoSRequest_arg_t arg = {};
|
||||
|
||||
smu_print("SMU UpdateUTMQoSRequest: sop_idx=%d nominal=%d urgent=%d lsdma=%d KBps\n",
|
||||
latency_sop_index, nominal_bandwidth_KBps,
|
||||
urgent_bandwidth_KBps, lsdma_bandwidth_KBps);
|
||||
|
||||
arg.LatencySopIndex = latency_sop_index;
|
||||
arg.NominalBandwidthKBps = nominal_bandwidth_KBps;
|
||||
arg.UrgentBandwidthKBps = urgent_bandwidth_KBps;
|
||||
arg.LsdmaBandwidthKBps = lsdma_bandwidth_KBps;
|
||||
|
||||
return dcn60_smu_send_msg_with_args(clk_mgr,
|
||||
DALSMC_MSG_UpdateUTMQoSRequest, arg.Args, NULL, NULL);
|
||||
}
|
||||
|
||||
bool dcn60_smu_get_msg_header_version(struct clk_mgr_internal *clk_mgr,
|
||||
uint32_t *version)
|
||||
{
|
||||
DALSMC_args_t args = {};
|
||||
|
||||
return dcn60_smu_send_msg_with_args(clk_mgr,
|
||||
DALSMC_MSG_GetMsgHeaderVersion, args, version, NULL);
|
||||
}
|
||||
|
||||
void dcn60_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, bool is_idle)
|
||||
{
|
||||
DALSMC_SetDisplayIdleOptimizations_arg_t arg = {};
|
||||
|
||||
arg.DfRequestDisabled = is_idle ? 1 : 0;
|
||||
arg.PhyRefClkOff = is_idle ? 1 : 0;
|
||||
arg.S0i2Rdy = is_idle ? 1 : 0;
|
||||
|
||||
smu_print("SMU SetDisplayIdleOptimizations: DfRequestDisabled=%d PhyRefClkOff=%d S0i2Rdy=%d\n",
|
||||
arg.DfRequestDisabled, arg.PhyRefClkOff, arg.S0i2Rdy);
|
||||
|
||||
dcn60_smu_send_msg_with_args(clk_mgr,
|
||||
DALSMC_MSG_SetDisplayIdleOptimizations, arg.Args, NULL, NULL);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright 2025 Advanced Micro Devices, Inc.
|
||||
|
||||
#ifndef __DCN60_CLK_MGR_SMU_MSG_H_
|
||||
#define __DCN60_CLK_MGR_SMU_MSG_H_
|
||||
|
||||
#include "os_types.h"
|
||||
#include "core_types.h"
|
||||
#include "dalsmc.h"
|
||||
|
||||
struct clk_mgr_internal;
|
||||
|
||||
unsigned int dcn60_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint16_t freq_mhz);
|
||||
void dcn60_smu_set_stutter_efficiency(struct clk_mgr_internal *clk_mgr,
|
||||
uint8_t base_efficiency, uint8_t low_power_efficiency);
|
||||
void dcn60_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, uint32_t freq_mhz);
|
||||
void dcn60_smu_set_pme_workaround(struct clk_mgr_internal *clk_mgr);
|
||||
void dcn60_smu_indicate_pstate_status(struct clk_mgr_internal *clk_mgr,
|
||||
bool allow_fclk, bool allow_uclk,
|
||||
bool wait_resp, bool drr_enable, bool alt_ch_enable);
|
||||
bool dcn60_smu_update_utm_qos_request(struct clk_mgr_internal *clk_mgr,
|
||||
uint32_t latency_sop_index,
|
||||
uint32_t nominal_bandwidth_KBps,
|
||||
uint32_t urgent_bandwidth_KBps,
|
||||
uint32_t lsdma_bandwidth_KBps);
|
||||
bool dcn60_smu_set_soc_utm_table(struct clk_mgr_internal *clk_mgr,
|
||||
long long dram_addr);
|
||||
bool dcn60_smu_get_dal_init_table(struct clk_mgr_internal *clk_mgr,
|
||||
const DalInitTable_t **init_table);
|
||||
bool dcn60_smu_get_msg_header_version(struct clk_mgr_internal *clk_mgr,
|
||||
uint32_t *version);
|
||||
void dcn60_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, bool is_idle);
|
||||
|
||||
#endif /* __DCN60_CLK_MGR_SMU_MSG_H_ */
|
||||
@@ -3027,13 +3027,14 @@ static struct dc_update_descriptor det_surface_update(
|
||||
elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
|
||||
}
|
||||
|
||||
if ((u->cm && u->cm->flags.bits.blend_enable) ||
|
||||
if ((u->cm && (u->cm->flags.bits.blend_enable ||
|
||||
u->cm->flags.bits.blend_enable != u->surface->cm.flags.bits.blend_enable)) ||
|
||||
(u->gamma && dce_use_lut(u->plane_info ? u->plane_info->format : u->surface->format))) {
|
||||
update_bits->gamma_change = 1;
|
||||
elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
|
||||
}
|
||||
|
||||
if (u->cm && (u->cm->flags.bits.lut3d_enable || u->cm->flags.bits.shaper_enable)) {
|
||||
if (u->cm && (u->cm->flags.bits.lut3d_enable || u->surface->cm.flags.bits.lut3d_enable)) {
|
||||
update_bits->lut_3d = 1;
|
||||
elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM);
|
||||
}
|
||||
@@ -3075,31 +3076,19 @@ static struct dc_update_descriptor det_surface_update(
|
||||
}
|
||||
};
|
||||
|
||||
if (u->cm->flags.bits.shaper_enable != u->surface->cm.flags.bits.shaper_enable
|
||||
|| u->cm->flags.bits.blend_enable != u->surface->cm.flags.bits.blend_enable
|
||||
|| u->cm->flags.bits.lut3d_enable != u->surface->cm.flags.bits.lut3d_enable
|
||||
|| u->cm->flags.bits.lut3d_dma_enable != u->surface->cm.flags.bits.lut3d_dma_enable) {
|
||||
update_bits->mcm_transfer_function_enable_change = 1;
|
||||
elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
|
||||
}
|
||||
|
||||
if ((u->cm->flags.all != blend_only_flags.all && u->cm->flags.all != 0) ||
|
||||
(u->surface->cm.flags.all != blend_only_flags.all && u->surface->cm.flags.all != 0)) {
|
||||
elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
|
||||
}
|
||||
}
|
||||
|
||||
if (update_bits->lut_3d &&
|
||||
!u->surface->cm.flags.bits.lut3d_dma_enable) {
|
||||
elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
|
||||
}
|
||||
|
||||
if (check_config->enable_legacy_fast_update &&
|
||||
(update_bits->gamma_change ||
|
||||
update_bits->gamut_remap_change ||
|
||||
update_bits->input_csc_change ||
|
||||
update_bits->cm_hist_change ||
|
||||
update_bits->coeff_reduction_change)) {
|
||||
update_bits->coeff_reduction_change ||
|
||||
update_bits->cursor_csc_color_matrix_change)) {
|
||||
elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL);
|
||||
}
|
||||
return overall_type;
|
||||
@@ -3403,6 +3392,10 @@ static void copy_surface_update_to_plane(
|
||||
srf_update->plane_info->dcc;
|
||||
surface->layer_index =
|
||||
srf_update->plane_info->layer_index;
|
||||
surface->scaling_linearity =
|
||||
srf_update->plane_info->scaling_linearity;
|
||||
surface->cositing =
|
||||
srf_update->plane_info->cositing;
|
||||
}
|
||||
|
||||
if (srf_update->gamma) {
|
||||
@@ -3441,46 +3434,6 @@ static void copy_surface_update_to_plane(
|
||||
memcpy(&surface->cm, srf_update->cm, sizeof(surface->cm));
|
||||
surface->cm.refcount = refcount;
|
||||
|
||||
#ifndef TRIM_CM2
|
||||
/* Populate mcm_luts from cm for legacy consumers (dml2, hwseq) */
|
||||
surface->mcm_luts.lut1d_func = &surface->cm.blend_func;
|
||||
surface->mcm_luts.shaper = &surface->cm.shaper_func;
|
||||
if (srf_update->cm->flags.bits.lut3d_dma_enable) {
|
||||
surface->mcm_luts.lut3d_data.lut3d_src = DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM;
|
||||
surface->mcm_luts.lut3d_data.gpu_mem_params.addr = surface->cm.lut3d_dma.addr;
|
||||
surface->mcm_luts.lut3d_data.gpu_mem_params.layout =
|
||||
(surface->cm.lut3d_dma.swizzle == CM_LUT_3D_SWIZZLE_LINEAR_RGB) ?
|
||||
DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_RGB :
|
||||
(surface->cm.lut3d_dma.swizzle == CM_LUT_3D_SWIZZLE_LINEAR_BGR) ?
|
||||
DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_BGR :
|
||||
DC_CM2_GPU_MEM_LAYOUT_1D_PACKED_LINEAR;
|
||||
surface->mcm_luts.lut3d_data.gpu_mem_params.format_params.format =
|
||||
(surface->cm.lut3d_dma.format == CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12MSB) ?
|
||||
DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12MSB :
|
||||
(surface->cm.lut3d_dma.format == CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12LSB) ?
|
||||
DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12LSB :
|
||||
DC_CM2_GPU_MEM_FORMAT_16161616_FLOAT_FP1_5_10;
|
||||
surface->mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias =
|
||||
surface->cm.lut3d_dma.bias;
|
||||
surface->mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale =
|
||||
surface->cm.lut3d_dma.scale;
|
||||
surface->mcm_luts.lut3d_data.gpu_mem_params.component_order =
|
||||
DC_CM2_GPU_MEM_PIXEL_COMPONENT_ORDER_RGBA;
|
||||
surface->mcm_luts.lut3d_data.gpu_mem_params.size = DC_CM2_GPU_MEM_SIZE_TRANSFORMED;
|
||||
surface->mcm_luts.lut3d_data.mpc_3dlut_enable = (srf_update->cm->flags.bits.lut3d_enable != 0);
|
||||
} else {
|
||||
surface->mcm_luts.lut3d_data.lut3d_src = DC_CM2_TRANSFER_FUNC_SOURCE_SYSMEM;
|
||||
surface->mcm_luts.lut3d_data.lut3d_func = &surface->cm.lut3d_func;
|
||||
}
|
||||
|
||||
if (srf_update->cm->flags.bits.shaper_enable &&
|
||||
srf_update->cm->flags.bits.lut3d_enable)
|
||||
surface->mcm_shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT;
|
||||
else if (srf_update->cm->flags.bits.shaper_enable)
|
||||
surface->mcm_shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER;
|
||||
else
|
||||
surface->mcm_shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL;
|
||||
#endif /* TRIM_CM2 */
|
||||
}
|
||||
|
||||
if (srf_update->hdr_mult.value)
|
||||
@@ -3491,12 +3444,6 @@ static void copy_surface_update_to_plane(
|
||||
surface->sdr_white_level_nits =
|
||||
srf_update->sdr_white_level_nits;
|
||||
|
||||
if (srf_update->cm &&
|
||||
(srf_update->cm->flags.bits.blend_enable ||
|
||||
srf_update->cm->flags.bits.shaper_enable ||
|
||||
srf_update->cm->flags.bits.lut3d_enable))
|
||||
surface->lut_bank_a = !surface->lut_bank_a;
|
||||
|
||||
if (srf_update->input_csc_color_matrix)
|
||||
surface->input_csc_color_matrix =
|
||||
*srf_update->input_csc_color_matrix;
|
||||
@@ -3658,6 +3605,9 @@ static void copy_stream_update_to_stream(struct dc *dc,
|
||||
if (update->sharpening_required)
|
||||
stream->sharpening_required = *update->sharpening_required;
|
||||
|
||||
if (update->blending_linearity)
|
||||
stream->blending_linearity = *update->blending_linearity;
|
||||
|
||||
if (update->drr_trigger_mode) {
|
||||
stream->drr_trigger_mode = *update->drr_trigger_mode;
|
||||
}
|
||||
@@ -5235,7 +5185,7 @@ static void commit_planes_for_stream(struct dc *dc,
|
||||
srf_updates[i].cm->flags.bits.lut3d_enable &&
|
||||
srf_updates[i].cm->flags.bits.lut3d_dma_enable &&
|
||||
dc->hwss.trigger_3dlut_dma_load)
|
||||
dc->hwss.trigger_3dlut_dma_load(dc, pipe_ctx);
|
||||
dc->hwss.trigger_3dlut_dma_load(pipe_ctx);
|
||||
|
||||
/*program triple buffer after lock based on flip type*/
|
||||
if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) {
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "dcn10/dcn10_hubbub.h"
|
||||
#include "dce/dmub_hw_lock_mgr.h"
|
||||
#include "link_service.h"
|
||||
#include "custom_float.h"
|
||||
|
||||
#define MAX_NUM_MCACHE 8
|
||||
|
||||
@@ -729,6 +730,386 @@ void get_fams2_visual_confirm_color(
|
||||
}
|
||||
}
|
||||
|
||||
static bool get_update_dchubp_dpp_flags_status(struct pipe_ctx *pipe)
|
||||
{
|
||||
if (!pipe->plane_state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((pipe->update_flags.raw ||
|
||||
dc_pipe_update_bits_is_any_set(&pipe->plane_state->update_bits) ||
|
||||
pipe->stream->update_flags.raw)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Function to check if any update flags are set
|
||||
static bool get_pipe_update_bits_status(struct pipe_ctx *pipe, struct dc_plane_state *plane, struct dc_stream_state *stream)
|
||||
{
|
||||
(void)stream;
|
||||
if (plane) {
|
||||
return (pipe->update_flags.bits.enable ||
|
||||
pipe->update_flags.bits.plane_changed ||
|
||||
pipe->update_flags.bits.opp_changed ||
|
||||
plane->update_bits.pixel_format_change ||
|
||||
plane->update_bits.horizontal_mirror_change ||
|
||||
plane->update_bits.rotation_change ||
|
||||
plane->update_bits.swizzle_change ||
|
||||
plane->update_bits.dcc_change ||
|
||||
plane->update_bits.bpp_change ||
|
||||
plane->update_bits.scaling_change ||
|
||||
plane->update_bits.plane_size_change);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void hwss_build_full_sequence(struct dc *dc,
|
||||
struct block_sequence block_sequence[MAX_HWSS_BLOCK_SEQUENCE_SIZE],
|
||||
unsigned int *num_steps,
|
||||
struct dc_state *context, bool program_phantom_pipe)
|
||||
{
|
||||
(void)program_phantom_pipe;
|
||||
struct dc_plane_state *plane = NULL;
|
||||
struct dc_stream_state *stream = NULL;
|
||||
struct pipe_ctx *current_pipe = NULL;
|
||||
struct pipe_ctx *pipe = NULL;
|
||||
struct dce_hwseq *hws = dc->hwseq;
|
||||
unsigned int i;
|
||||
*num_steps = 0; // Initialize to 0
|
||||
struct block_sequence_state seq_state = { .steps = block_sequence, .num_steps = num_steps };
|
||||
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++)
|
||||
dc->hwss.detect_pipe_changes(dc->current_state, context, &dc->current_state->res_ctx.pipe_ctx[i],
|
||||
&context->res_ctx.pipe_ctx[i]);
|
||||
|
||||
/* Program triplebuffer if enabled */
|
||||
if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) {
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
pipe = &context->res_ctx.pipe_ctx[i];
|
||||
|
||||
if (pipe->plane_state) {
|
||||
/* Turn off triple buffer for full update */
|
||||
hwss_add_hubp_program_triplebuffer(&seq_state, dc, pipe, pipe->plane_state->triplebuffer_flips);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Count hubp usage and force pstate change if needed */
|
||||
unsigned int prev_hubp_count = 0;
|
||||
unsigned int hubp_count = 0;
|
||||
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
if (dc->current_state->res_ctx.pipe_ctx[i].plane_state)
|
||||
prev_hubp_count++;
|
||||
if (context->res_ctx.pipe_ctx[i].plane_state)
|
||||
hubp_count++;
|
||||
}
|
||||
|
||||
if (prev_hubp_count == 0 && hubp_count > 0) {
|
||||
if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
|
||||
hwss_add_hubbub_force_pstate_change_control(&seq_state, dc->res_pool->hubbub, true, false);
|
||||
}
|
||||
|
||||
/* When disabling phantom pipes, turn on phantom OTG first */
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct dc_stream_state *pipe_stream = dc->current_state->res_ctx.pipe_ctx[i].stream;
|
||||
|
||||
pipe = &dc->current_state->res_ctx.pipe_ctx[i];
|
||||
|
||||
if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && pipe_stream &&
|
||||
dc_state_get_pipe_subvp_type(dc->current_state, pipe) == SUBVP_PHANTOM) {
|
||||
struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg;
|
||||
|
||||
if (tg->funcs->enable_crtc) {
|
||||
if (dc->hwseq->funcs.blank_pixel_data_sequence)
|
||||
dc->hwseq->funcs.blank_pixel_data_sequence(dc, pipe, true, &seq_state);
|
||||
hwss_add_tg_enable_crtc(&seq_state, tg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* OTG blank before disabling all front ends */
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
|
||||
&& !context->res_ctx.pipe_ctx[i].top_pipe
|
||||
&& !context->res_ctx.pipe_ctx[i].prev_odm_pipe
|
||||
&& context->res_ctx.pipe_ctx[i].stream) {
|
||||
|
||||
if (dc->hwseq->funcs.blank_pixel_data_sequence) {
|
||||
dc->hwseq->funcs.blank_pixel_data_sequence(dc, &context->res_ctx.pipe_ctx[i],
|
||||
true, &seq_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Disconnect mpcc for pipes being disabled or with opp changes */
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
|
||||
|| context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) {
|
||||
struct hubbub *hubbub = dc->res_pool->hubbub;
|
||||
|
||||
/* Phantom pipe DET should be 0, but if a pipe in use is being transitioned to phantom
|
||||
* then we want to do the programming here (effectively it's being disabled). If we do
|
||||
* the programming later the DET won't be updated until the OTG for the phantom pipe is
|
||||
* turned on (i.e. in an MCLK switch) which can come in too late and cause issues with
|
||||
* DET allocation.
|
||||
*/
|
||||
if ((context->res_ctx.pipe_ctx[i].update_flags.bits.disable ||
|
||||
(context->res_ctx.pipe_ctx[i].plane_state &&
|
||||
dc_state_get_pipe_subvp_type(context, &context->res_ctx.pipe_ctx[i]) ==
|
||||
SUBVP_PHANTOM))) {
|
||||
|
||||
if (hubbub->funcs->program_det_size) {
|
||||
hwss_add_hubp_program_det_size(&seq_state, hubbub,
|
||||
dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);
|
||||
}
|
||||
|
||||
if (dc->res_pool->hubbub->funcs->program_det_segments) {
|
||||
hwss_add_hubp_program_det_segments(&seq_state, hubbub,
|
||||
dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (hws->funcs.plane_atomic_disconnect_sequence)
|
||||
hws->funcs.plane_atomic_disconnect_sequence(dc, dc->current_state,
|
||||
&dc->current_state->res_ctx.pipe_ctx[i], &seq_state);
|
||||
}
|
||||
}
|
||||
|
||||
/* update ODM for blanked OTG master pipes */
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
pipe = &context->res_ctx.pipe_ctx[i];
|
||||
if (resource_is_pipe_type(pipe, OTG_MASTER) &&
|
||||
!resource_is_pipe_type(pipe, DPP_PIPE) &&
|
||||
pipe->update_flags.bits.odm) {
|
||||
if (hws->funcs.update_odm_sequence)
|
||||
hws->funcs.update_odm_sequence(dc, context, pipe, &seq_state);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
pipe = &context->res_ctx.pipe_ctx[i];
|
||||
if (pipe->update_flags.bits.disable) {
|
||||
struct cm_hist_control hist_disable = { .channels_enabled = 0 };
|
||||
|
||||
hwss_add_dpp_program_cm_hist(&seq_state, pipe->plane_res.dpp,
|
||||
hist_disable, COLOR_SPACE_UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
pipe = &context->res_ctx.pipe_ctx[i];
|
||||
|
||||
if (pipe->plane_state && !pipe->top_pipe) {
|
||||
while (pipe) {
|
||||
if (pipe->stream &&
|
||||
dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) {
|
||||
if (hws->funcs.program_pipe_sequence)
|
||||
hws->funcs.program_pipe_sequence(dc, pipe, context, &seq_state);
|
||||
}
|
||||
|
||||
pipe = pipe->bottom_pipe;
|
||||
}
|
||||
}
|
||||
|
||||
/* Program secondary blending tree and writeback pipes */
|
||||
pipe = &context->res_ctx.pipe_ctx[i];
|
||||
if (!pipe->top_pipe && !pipe->prev_odm_pipe
|
||||
&& pipe->stream && pipe->stream->num_wb_info > 0
|
||||
&& (pipe->update_flags.raw || (pipe->plane_state && dc_pipe_update_bits_is_any_set(&pipe->plane_state->update_bits))
|
||||
|| pipe->stream->update_flags.raw)) {
|
||||
|
||||
if (hws->funcs.program_all_writeback_pipes_in_tree_sequence)
|
||||
hws->funcs.program_all_writeback_pipes_in_tree_sequence(dc, pipe->stream,
|
||||
context, &seq_state);
|
||||
}
|
||||
|
||||
/* Avoid underflow by check of pipe line read when adding 2nd plane. */
|
||||
if (hws->wa.wait_hubpret_read_start_during_mpo_transition &&
|
||||
!pipe->top_pipe &&
|
||||
pipe->stream &&
|
||||
pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start &&
|
||||
dc->current_state->stream_status[0].plane_count == 1 &&
|
||||
context->stream_status[0].plane_count > 1) {
|
||||
hwss_add_hubp_wait_pipe_read_start(&seq_state, pipe->plane_res.hubp);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
current_pipe = &context->res_ctx.pipe_ctx[i];
|
||||
|
||||
while (current_pipe) {
|
||||
plane = current_pipe->plane_state;
|
||||
stream = current_pipe->stream;
|
||||
bool is_phantom = (dc_state_get_pipe_subvp_type(context, current_pipe) == SUBVP_PHANTOM);
|
||||
|
||||
if (get_update_dchubp_dpp_flags_status(current_pipe)) {
|
||||
if (!is_phantom && plane && stream) {
|
||||
if (get_pipe_update_bits_status(current_pipe, plane, stream)) {
|
||||
struct plane_size size = plane->plane_size;
|
||||
|
||||
size.surface_size = current_pipe->plane_res.scl_data.viewport;
|
||||
hwss_add_hubp_program_surface_config(&seq_state, current_pipe->plane_res.hubp,
|
||||
plane->format, &plane->tiling_info, size, plane->rotation, &plane->dcc,
|
||||
plane->horizontal_mirror, 0);
|
||||
}
|
||||
|
||||
if (current_pipe->plane_res.hubp->funcs->hubp_program_mcache_id_and_split_coordinate)
|
||||
hwss_add_hubp_program_mcache_id(&seq_state, current_pipe->plane_res.hubp, ¤t_pipe->mcache_regs);
|
||||
|
||||
if (current_pipe->plane_res.dpp->funcs->dpp_program_upsp) {
|
||||
block_sequence[*num_steps].params.program_upsp_params.pipe_ctx = current_pipe;
|
||||
block_sequence[*num_steps].func = DPP_PROGRAM_UPSP;
|
||||
(*num_steps)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
current_pipe = current_pipe->bottom_pipe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hwss_build_post_unlock_full_sequence(struct dc *dc,
|
||||
struct block_sequence block_sequence[MAX_HWSS_BLOCK_SEQUENCE_SIZE],
|
||||
unsigned int *num_steps,
|
||||
struct dc_state *context)
|
||||
{
|
||||
unsigned int i;
|
||||
struct dce_hwseq *hwseq = dc->hwseq;
|
||||
*num_steps = 0; // Initialize to 0
|
||||
struct block_sequence_state seq_state = { .steps = block_sequence, .num_steps = num_steps };
|
||||
|
||||
/* Reset OPP for pipes transitioning from OPP_HEAD to non-OPP_HEAD */
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
if (resource_is_pipe_type(&dc->current_state->res_ctx.pipe_ctx[i], OPP_HEAD) &&
|
||||
!resource_is_pipe_type(&context->res_ctx.pipe_ctx[i], OPP_HEAD)) {
|
||||
|
||||
if (dc->hwss.post_unlock_reset_opp_sequence)
|
||||
dc->hwss.post_unlock_reset_opp_sequence(dc, &dc->current_state->res_ctx.pipe_ctx[i],
|
||||
&seq_state);
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable planes that are being disabled */
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) {
|
||||
if (dc->hwss.disable_plane_sequence)
|
||||
dc->hwss.disable_plane_sequence(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i],
|
||||
&seq_state);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for flip pending on pipes being enabled */
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
||||
|
||||
if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable &&
|
||||
dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) {
|
||||
|
||||
unsigned int polling_interval_us;
|
||||
polling_interval_us = 1;
|
||||
hwss_add_hubp_wait_flip_pending(&seq_state, pipe->plane_res.hubp, 100000, polling_interval_us);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for double buffer pending when ODM slice count increases */
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
||||
struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
|
||||
|
||||
if (resource_is_pipe_type(old_pipe, OTG_MASTER) && resource_is_pipe_type(pipe, OTG_MASTER) &&
|
||||
resource_get_odm_slice_count(old_pipe) < resource_get_odm_slice_count(pipe) &&
|
||||
dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) {
|
||||
|
||||
unsigned int polling_interval_us;
|
||||
polling_interval_us = 1;
|
||||
hwss_add_tg_wait_double_buffer_pending(&seq_state, pipe->stream_res.tg, 100000, polling_interval_us);
|
||||
}
|
||||
}
|
||||
|
||||
/* Force pstate change control to false */
|
||||
if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
|
||||
hwss_add_hubbub_force_pstate_change_control(&seq_state, dc->res_pool->hubbub, false, false);
|
||||
|
||||
/* Program phantom pipes */
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
||||
|
||||
if (pipe->plane_state && !pipe->top_pipe) {
|
||||
while (pipe) {
|
||||
if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
|
||||
/* Apply update flags for phantom pipes using existing HWS functions */
|
||||
if (dc->hwss.apply_update_flags_for_phantom)
|
||||
hwss_add_hws_apply_update_flags_for_phantom(&seq_state, pipe);
|
||||
if (dc->hwss.update_phantom_vp_position)
|
||||
hwss_add_hws_update_phantom_vp_position(&seq_state, dc, context, pipe);
|
||||
|
||||
/* Program the phantom pipe - use program_pipe_sequence if available */
|
||||
if (dc->hwseq && dc->hwseq->funcs.program_pipe_sequence)
|
||||
dc->hwseq->funcs.program_pipe_sequence(dc, pipe, context, &seq_state);
|
||||
}
|
||||
pipe = pipe->bottom_pipe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
||||
|
||||
while (pipe) {
|
||||
struct dc_plane_state *plane = pipe->plane_state;
|
||||
struct dc_stream_state *stream = pipe->stream;
|
||||
bool is_phantom = (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM);
|
||||
|
||||
if (get_update_dchubp_dpp_flags_status(pipe)) {
|
||||
if (is_phantom && plane && stream) {
|
||||
if (get_pipe_update_bits_status(pipe, plane, stream)) {
|
||||
struct plane_size size = plane->plane_size;
|
||||
|
||||
size.surface_size = pipe->plane_res.scl_data.viewport;
|
||||
hwss_add_hubp_program_surface_config(&seq_state, pipe->plane_res.hubp,
|
||||
plane->format, &plane->tiling_info, size, plane->rotation, &plane->dcc,
|
||||
plane->horizontal_mirror, 0);
|
||||
}
|
||||
|
||||
if (pipe->plane_res.hubp->funcs->hubp_program_mcache_id_and_split_coordinate)
|
||||
hwss_add_hubp_program_mcache_id(&seq_state, pipe->plane_res.hubp, &pipe->mcache_regs);
|
||||
}
|
||||
}
|
||||
pipe = pipe->bottom_pipe;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update force pstate if hwseq is available */
|
||||
if (hwseq && hwseq->funcs.update_force_pstate)
|
||||
hwss_add_update_force_pstate(&seq_state, dc, context);
|
||||
|
||||
/* Program MALL pipe configuration */
|
||||
if (hwseq && hwseq->funcs.program_mall_pipe_config_sequence)
|
||||
hwseq->funcs.program_mall_pipe_config_sequence(dc, context, &seq_state);
|
||||
|
||||
/* Apply DEDCN21 147 WA if needed */
|
||||
if (hwseq && hwseq->wa.DEGVIDCN21)
|
||||
hwss_add_hubbub_apply_dedcn21_147_wa(&seq_state, dc->res_pool->hubbub);
|
||||
|
||||
/* Handle stutter underflow WA during MPO transitions */
|
||||
if (hwseq && hwseq->wa.disallow_self_refresh_during_multi_plane_transition &&
|
||||
dc->current_state->stream_status[0].plane_count == 1 &&
|
||||
context->stream_status[0].plane_count > 1) {
|
||||
|
||||
hwss_add_hubbub_allow_self_refresh_control(&seq_state, dc->res_pool->hubbub, false,
|
||||
&hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied);
|
||||
|
||||
/* Get frame count for WA state tracking - this needs to be done immediately after the above call */
|
||||
if (dc->res_pool->timing_generators[0]->funcs->get_frame_count) {
|
||||
hwss_add_tg_get_frame_count(&seq_state, dc->res_pool->timing_generators[0],
|
||||
&hwseq->wa_state.disallow_self_refresh_during_multi_plane_transition_applied_on_frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hwss_build_fast_sequence(struct dc *dc,
|
||||
struct dc_dmub_cmd *dc_dmub_cmd,
|
||||
unsigned int dmub_cmd_count,
|
||||
@@ -1058,6 +1439,16 @@ void hwss_build_fast_sequence(struct dc *dc,
|
||||
(*num_steps)++;
|
||||
}
|
||||
|
||||
if (current_mpc_pipe->plane_state->update_bits.lut_3d &&
|
||||
current_mpc_pipe->plane_state->cm.flags.bits.lut3d_dma_enable &&
|
||||
current_mpc_pipe->plane_state->cm.flags.bits.shaper_enable &&
|
||||
current_mpc_pipe->plane_state->cm.flags.bits.lut3d_enable &&
|
||||
current_mpc_pipe->plane_res.hubp->funcs->hubp_enable_3dlut_fl) {
|
||||
block_sequence[*num_steps].params.hubp_enable_3dlut_fl_params.hubp =
|
||||
current_mpc_pipe->plane_res.hubp;
|
||||
block_sequence[*num_steps].func = HUBP_ENABLE_3DLUT_FL;
|
||||
(*num_steps)++;
|
||||
}
|
||||
if (hws->funcs.set_input_transfer_func && current_mpc_pipe->plane_state->update_bits.gamma_change) {
|
||||
block_sequence[*num_steps].params.set_input_transfer_func_params.dc = dc;
|
||||
block_sequence[*num_steps].params.set_input_transfer_func_params.pipe_ctx = current_mpc_pipe;
|
||||
@@ -1066,6 +1457,24 @@ void hwss_build_fast_sequence(struct dc *dc,
|
||||
(*num_steps)++;
|
||||
}
|
||||
|
||||
if (current_mpc_pipe->plane_state->update_bits.hdr_mult) {
|
||||
struct fixed31_32 multiplier = current_mpc_pipe->plane_state->hdr_mult;
|
||||
uint32_t hw_mult = 0x1f000; // 1.0 default multiplier
|
||||
struct custom_float_format fmt;
|
||||
|
||||
fmt.exponenta_bits = 6;
|
||||
fmt.mantissa_bits = 12;
|
||||
fmt.sign = true;
|
||||
|
||||
if (!dc_fixpt_eq(multiplier, dc_fixpt_from_int(0)) && // check != 0
|
||||
convert_to_custom_float_format(multiplier, &fmt, &hw_mult)) {
|
||||
block_sequence[*num_steps].params.dpp_set_hdr_multiplier_params.dpp = current_mpc_pipe->plane_res.dpp;
|
||||
block_sequence[*num_steps].params.dpp_set_hdr_multiplier_params.hw_mult = hw_mult;
|
||||
block_sequence[*num_steps].func = DPP_SET_HDR_MULTIPLIER;
|
||||
(*num_steps)++;
|
||||
}
|
||||
}
|
||||
|
||||
if (dc->hwss.program_gamut_remap &&
|
||||
(current_mpc_pipe->plane_state->update_bits.gamut_remap_change ||
|
||||
current_mpc_pipe->stream->update_flags.bits.gamut_remap)) {
|
||||
@@ -1279,6 +1688,9 @@ void hwss_execute_sequence(struct dc *dc,
|
||||
case DPP_SET_OUTPUT_TRANSFER_FUNC:
|
||||
hws->funcs.set_output_transfer_func(¶ms->set_output_transfer_func_params);
|
||||
break;
|
||||
case DPP_PROGRAM_UPSP:
|
||||
hwss_program_upsp(params);
|
||||
break;
|
||||
case MPC_UPDATE_VISUAL_CONFIRM:
|
||||
dc->hwss.update_visual_confirm_color(params->update_visual_confirm_params.dc,
|
||||
params->update_visual_confirm_params.pipe_ctx,
|
||||
@@ -1900,7 +2312,8 @@ void hwss_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx)
|
||||
.xfm = pipe_ctx->plane_res.xfm,
|
||||
.dpp = pipe_ctx->plane_res.dpp,
|
||||
.mpc = dc->res_pool->mpc,
|
||||
.mpcc_id = pipe_ctx->plane_res.hubp->inst,
|
||||
.mpcc_id = pipe_ctx->plane_res.hubp ?
|
||||
pipe_ctx->plane_res.hubp->inst : 0,
|
||||
.is_top_pipe = resource_is_pipe_type(pipe_ctx, OPP_HEAD),
|
||||
.stream = pipe_ctx->stream,
|
||||
}
|
||||
@@ -2448,6 +2861,22 @@ void hwss_program_bias_and_scale(union block_sequence_params *params)
|
||||
dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params);
|
||||
}
|
||||
|
||||
void hwss_program_upsp(union block_sequence_params *params)
|
||||
{
|
||||
struct pipe_ctx *pipe_ctx = params->program_upsp_params.pipe_ctx;
|
||||
struct dpp *dpp = pipe_ctx->plane_res.dpp;
|
||||
struct dscl_prog_data *dscl_prog_data = &pipe_ctx->plane_res.scl_data.dscl_prog_data;
|
||||
|
||||
if (!dpp || !dscl_prog_data)
|
||||
return;
|
||||
|
||||
if (dpp && dpp->funcs->dpp_program_upsp) {
|
||||
// program upsampler
|
||||
dpp->funcs->dpp_program_upsp(dpp,
|
||||
dscl_prog_data);
|
||||
}
|
||||
}
|
||||
|
||||
void hwss_power_on_mpc_mem_pwr(union block_sequence_params *params)
|
||||
{
|
||||
struct mpc *mpc = params->power_on_mpc_mem_pwr_params.mpc;
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
#include "dcn401/dcn401_resource.h"
|
||||
#include "dcn42/dcn42_resource.h"
|
||||
#include "dcn42b/dcn42b_resource.h"
|
||||
#include "dcn60/dcn60_resource.h"
|
||||
#if defined(CONFIG_DRM_AMD_DC_FP)
|
||||
#include "dc_spl_translate.h"
|
||||
#endif
|
||||
@@ -261,6 +262,9 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
|
||||
case AMDGPU_FAMILY_GC_11_5_4:
|
||||
dc_version = DCN_VERSION_4_2;
|
||||
break;
|
||||
case AMDGPU_FAMILY_GC_13_0_1:
|
||||
dc_version = DCN_VERSION_6_0;
|
||||
break;
|
||||
default:
|
||||
dc_version = DCE_VERSION_UNKNOWN;
|
||||
break;
|
||||
@@ -383,6 +387,9 @@ struct resource_pool *dc_create_resource_pool(struct dc *dc,
|
||||
case DCN_VERSION_4_2B:
|
||||
res_pool = dcn42b_create_resource_pool(init_data, dc);
|
||||
break;
|
||||
case DCN_VERSION_6_0:
|
||||
res_pool = dcn60_create_resource_pool(init_data, dc);
|
||||
break;
|
||||
#endif /* CONFIG_DRM_AMD_DC_FP */
|
||||
default:
|
||||
break;
|
||||
@@ -818,6 +825,36 @@ static enum dc_pixel_format convert_pixel_format_to_dalsurface(
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
|
||||
dal_pixel_format = PIXEL_FORMAT_420BPP10;
|
||||
break;
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P208:
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P208:
|
||||
dal_pixel_format = PIXEL_FORMAT_422BPP8;
|
||||
break;
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P210:
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P210:
|
||||
dal_pixel_format = PIXEL_FORMAT_422BPP10;
|
||||
break;
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P212:
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P212:
|
||||
dal_pixel_format = PIXEL_FORMAT_422BPP12;
|
||||
break;
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_YCrYCb:
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_YCbYCr:
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrYCbY:
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbYCrY:
|
||||
dal_pixel_format = PIXEL_FORMAT_422BPP8;
|
||||
break;
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_YCrYCb:
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_YCbYCr:
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_CrYCbY:
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_CbYCrY:
|
||||
dal_pixel_format = PIXEL_FORMAT_422BPP10;
|
||||
break;
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_YCrYCb:
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_YCbYCr:
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_CrYCbY:
|
||||
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_CbYCrY:
|
||||
dal_pixel_format = PIXEL_FORMAT_422BPP12;
|
||||
break;
|
||||
case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
|
||||
case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
|
||||
default:
|
||||
@@ -1516,6 +1553,15 @@ void resource_build_test_pattern_params(struct resource_context *res_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
enum upsp_mode resource_is_upsp_required(enum surface_pixel_format format)
|
||||
{
|
||||
if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN && format <= SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb) //420 Formats
|
||||
return UPSP_HORIZONTAL_VERTICAL_UPSAMPLING;
|
||||
if (format > SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb && format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END) //422 Formats
|
||||
return UPSP_HORIZONTAL_UPSAMPLING_ONLY;
|
||||
return UPSP_BYPASS;
|
||||
}
|
||||
|
||||
bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
|
||||
{
|
||||
const struct dc_plane_state *plane_state = pipe_ctx->plane_state;
|
||||
@@ -1561,6 +1607,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
|
||||
pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
|
||||
|
||||
pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha;
|
||||
pipe_ctx->plane_res.scl_data.upsp = resource_is_upsp_required(plane_state->format);
|
||||
|
||||
// Convert pipe_ctx to respective input params for SPL
|
||||
translate_SPL_in_params_from_pipe_ctx(pipe_ctx, spl_in);
|
||||
|
||||
@@ -1155,3 +1155,15 @@ bool dc_state_is_subvp_in_use(struct dc_state *state)
|
||||
|
||||
return false;
|
||||
}
|
||||
bool dc_state_is_alt_in_use(const struct dc *dc, const struct dc_state *state)
|
||||
{
|
||||
uint32_t i;
|
||||
const struct pipe_ctx *pipe;
|
||||
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
pipe = &state->res_ctx.pipe_ctx[i];
|
||||
if (pipe->p_state_type == P_STATE_ALT)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -405,6 +405,7 @@ bool dc_stream_program_cursor_attributes(
|
||||
{
|
||||
struct dc *dc;
|
||||
bool reset_idle_optimizations = false;
|
||||
bool should_release_dmub_hw_control_lock = false;
|
||||
|
||||
if (!stream)
|
||||
return false;
|
||||
@@ -413,6 +414,13 @@ bool dc_stream_program_cursor_attributes(
|
||||
|
||||
if (dc_stream_set_cursor_attributes(stream, attributes)) {
|
||||
dc_z10_restore(dc);
|
||||
if (dc->hwss.dmub_hw_control_lock) {
|
||||
if (dc_state_is_alt_in_use(dc, dc->current_state) &&
|
||||
!dc_dmub_srv_is_cursor_offload_enabled(dc)) {
|
||||
dc->hwss.dmub_hw_control_lock(dc, dc->current_state, true);
|
||||
should_release_dmub_hw_control_lock = true;
|
||||
}
|
||||
}
|
||||
/* disable idle optimizations while updating cursor */
|
||||
if (dc->idle_optimizations_allowed) {
|
||||
dc_allow_idle_optimizations(dc, false);
|
||||
@@ -425,6 +433,10 @@ bool dc_stream_program_cursor_attributes(
|
||||
if (reset_idle_optimizations && !dc->debug.disable_dmub_reallow_idle)
|
||||
dc_allow_idle_optimizations(dc, true);
|
||||
|
||||
if (dc->hwss.dmub_hw_control_lock) {
|
||||
if (should_release_dmub_hw_control_lock)
|
||||
dc->hwss.dmub_hw_control_lock(dc, dc->current_state, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -507,6 +519,7 @@ bool dc_stream_program_cursor_position(
|
||||
struct dc *dc;
|
||||
bool reset_idle_optimizations = false;
|
||||
const struct dc_cursor_position *old_position;
|
||||
bool should_release_dmub_hw_control_lock = false;
|
||||
|
||||
if (!stream)
|
||||
return false;
|
||||
@@ -517,6 +530,13 @@ bool dc_stream_program_cursor_position(
|
||||
if (dc_stream_set_cursor_position(stream, position)) {
|
||||
dc_z10_restore(dc);
|
||||
|
||||
if (dc->hwss.dmub_hw_control_lock) {
|
||||
if (dc_state_is_alt_in_use(dc, dc->current_state) &&
|
||||
!dc_dmub_srv_is_cursor_offload_enabled(dc)) {
|
||||
dc->hwss.dmub_hw_control_lock(dc, dc->current_state, true);
|
||||
should_release_dmub_hw_control_lock = true;
|
||||
}
|
||||
}
|
||||
/* disable idle optimizations if enabling cursor */
|
||||
if (dc->idle_optimizations_allowed &&
|
||||
(!old_position->enable || dc->debug.exit_idle_opt_for_cursor_updates) &&
|
||||
@@ -567,6 +587,10 @@ bool dc_stream_program_cursor_position(
|
||||
}
|
||||
}
|
||||
|
||||
if (dc->hwss.dmub_hw_control_lock) {
|
||||
if (should_release_dmub_hw_control_lock)
|
||||
dc->hwss.dmub_hw_control_lock(dc, dc->current_state, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -967,6 +991,7 @@ void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream)
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO - move to per plane ownership? */
|
||||
/*
|
||||
* dc_stream_get_3dlut()
|
||||
* Requirements:
|
||||
@@ -1018,7 +1043,6 @@ void dc_stream_release_3dlut_for_stream(
|
||||
if (rmcm_3dlut) {
|
||||
rmcm_3dlut->isInUse = false;
|
||||
rmcm_3dlut->stream = NULL;
|
||||
rmcm_3dlut->protection_bits = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1030,7 +1054,6 @@ void dc_stream_init_rmcm_3dlut(struct dc *dc)
|
||||
for (unsigned int i = 0; i < num_rmcm; i++) {
|
||||
dc->res_pool->rmcm_3dlut[i].isInUse = false;
|
||||
dc->res_pool->rmcm_3dlut[i].stream = NULL;
|
||||
dc->res_pool->rmcm_3dlut[i].protection_bits = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ struct dcn_dsc_reg_state;
|
||||
struct dcn_optc_reg_state;
|
||||
struct dcn_dccg_reg_state;
|
||||
|
||||
#define DC_VER "3.2.391"
|
||||
#define DC_VER "3.2.392"
|
||||
|
||||
/**
|
||||
* MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC
|
||||
@@ -174,6 +174,13 @@ struct dc_plane_cap {
|
||||
uint32_t fp16 : 1;
|
||||
uint32_t p010 : 1;
|
||||
uint32_t ayuv : 1;
|
||||
uint32_t yuy2 : 1; // Packed 422 8bpc
|
||||
uint32_t y210 : 1; // Packed 422 10bpc
|
||||
uint32_t y212 : 1; // Packed 422 12bpc
|
||||
uint32_t p208 : 1; // Planar 422 8bpc
|
||||
uint32_t p210 : 1; // Planar 422 10bpc
|
||||
uint32_t p212 : 1; // Planar 422 12bpc
|
||||
/* Not all caps will be used/supported */
|
||||
} pixel_format_support;
|
||||
// max upscaling factor x1000
|
||||
// upscaling factors are always >= 1
|
||||
@@ -240,6 +247,7 @@ struct rom_curve_caps {
|
||||
* @ogam_ram: programmable out/blend gamma LUT
|
||||
* @ocsc: output color space conversion
|
||||
* @dgam_rom_for_yuv: pre-defined degamma LUT for YUV planes
|
||||
* @upsp_pre_scaler: Ability to upsample 420/422 before scaling
|
||||
* @dgam_rom_caps: pre-definied curve caps for degamma 1D LUT
|
||||
* @ogam_rom_caps: pre-definied curve caps for regamma 1D LUT
|
||||
*
|
||||
@@ -256,6 +264,7 @@ struct dpp_color_caps {
|
||||
uint16_t ogam_ram : 1;
|
||||
uint16_t ocsc : 1;
|
||||
uint16_t dgam_rom_for_yuv : 1;
|
||||
uint16_t upsp_pre_scaler : 1;
|
||||
struct rom_curve_caps dgam_rom_caps;
|
||||
struct rom_curve_caps ogam_rom_caps;
|
||||
};
|
||||
@@ -617,6 +626,7 @@ struct dc_config {
|
||||
bool unify_link_enc_assignment;
|
||||
bool enable_cursor_offload;
|
||||
bool dp_connector_no_native_i2c;
|
||||
unsigned int link_index_with_no_ddc;
|
||||
bool frame_update_cmd_version2;
|
||||
struct spl_sharpness_range dcn_sharpness_range;
|
||||
struct spl_sharpness_range dcn_override_sharpness_range;
|
||||
@@ -785,6 +795,7 @@ struct dc_clocks {
|
||||
*/
|
||||
bool fw_based_mclk_switching;
|
||||
bool fw_based_mclk_switching_shut_down;
|
||||
bool alt_ch_pstate_switch;
|
||||
int prev_num_ways;
|
||||
enum dtm_pstate dtm_level;
|
||||
int max_supported_dppclk_khz;
|
||||
@@ -795,6 +806,18 @@ struct dc_clocks {
|
||||
int idle_fclk_khz;
|
||||
int subvp_prefetch_dramclk_khz;
|
||||
int subvp_prefetch_fclk_khz;
|
||||
/* deprecated: use _KBps variants — will be removed after DML update */
|
||||
unsigned int utm_urgent_bandwidth_lb_Kbps;
|
||||
unsigned int utm_nominal_bandwidth_lb_Kbps;
|
||||
unsigned int utm_urgent_bandwidth_lb_KBps;
|
||||
unsigned int utm_nominal_bandwidth_lb_KBps;
|
||||
unsigned int utm_latency_ub_index;
|
||||
unsigned int utm_lsdma_bandwidth_lb_KBps;
|
||||
unsigned int utm_nominal_max_latency_ub_ns;
|
||||
unsigned int utm_nominal_avg_latency_ub_ns;
|
||||
/* deprecated: use _KBps variant — will be removed after DML update */
|
||||
unsigned int required_avg_active_bandwidth_Kbps;
|
||||
unsigned int required_avg_active_bandwidth_KBps;
|
||||
|
||||
/* Stutter efficiency is technically not clock values
|
||||
* but stored here so the values are part of the update_clocks call similar to num_ways
|
||||
@@ -1436,6 +1459,7 @@ struct dc_transfer_func {
|
||||
enum dc_transfer_func_predefined tf;
|
||||
/* FP16 1.0 reference level in nits, default is 80 nits, only for PQ*/
|
||||
uint32_t sdr_ref_white_level;
|
||||
struct fixed31_32 hdr_multiplier;
|
||||
union {
|
||||
struct pwl_params pwl;
|
||||
struct dc_transfer_func_distributed_points tf_pts;
|
||||
@@ -1486,13 +1510,11 @@ struct lut_mem_mapping {
|
||||
struct dc_rmcm_3dlut {
|
||||
bool isInUse;
|
||||
const struct dc_stream_state *stream;
|
||||
uint8_t protection_bits;
|
||||
};
|
||||
|
||||
struct dc_3dlut {
|
||||
struct kref refcount;
|
||||
struct tetrahedral_params lut_3d;
|
||||
struct fixed31_32 hdr_multiplier;
|
||||
union dc_3dlut_state state;
|
||||
};
|
||||
|
||||
@@ -1572,7 +1594,6 @@ struct pipe_update_bits {
|
||||
uint32_t stereo_format_change:1;
|
||||
uint32_t lut_3d:1;
|
||||
uint32_t tmz_changed:1;
|
||||
uint32_t mcm_transfer_function_enable_change:1; /* disable or enable MCM transfer func */
|
||||
uint32_t full_update:1;
|
||||
uint32_t sdr_white_level_nits:1;
|
||||
uint32_t cm_hist_change:1;
|
||||
@@ -1617,7 +1638,6 @@ static inline void dc_pipe_update_bits_set_full(struct pipe_update_bits *flags)
|
||||
flags->stereo_format_change = 1;
|
||||
flags->lut_3d = 1;
|
||||
flags->tmz_changed = 1;
|
||||
flags->mcm_transfer_function_enable_change = 1;
|
||||
flags->full_update = 1;
|
||||
flags->sdr_white_level_nits = 1;
|
||||
flags->cm_hist_change = 1;
|
||||
@@ -1651,7 +1671,6 @@ static inline bool dc_pipe_update_bits_is_any_set(const struct pipe_update_bits
|
||||
flags->stereo_format_change ||
|
||||
flags->lut_3d ||
|
||||
flags->tmz_changed ||
|
||||
flags->mcm_transfer_function_enable_change ||
|
||||
flags->full_update ||
|
||||
flags->sdr_white_level_nits ||
|
||||
flags->cm_hist_change;
|
||||
@@ -1686,18 +1705,16 @@ struct dc_plane_state {
|
||||
enum dc_color_space color_space;
|
||||
|
||||
#ifndef TRIM_CM2
|
||||
// TODO: No longer used, remove
|
||||
bool lut_bank_a;
|
||||
struct dc_hdr_static_metadata hdr_static_ctx;
|
||||
|
||||
struct dc_3dlut lut3d_func;
|
||||
struct dc_transfer_func in_shaper_func;
|
||||
struct dc_transfer_func blend_tf;
|
||||
enum dc_cm2_shaper_3dlut_setting mcm_shaper_3dlut_setting;
|
||||
bool mcm_lut1d_enable;
|
||||
struct dc_cm2_func_luts mcm_luts;
|
||||
#endif /* TRIM_CM2 */
|
||||
bool lut_bank_a;
|
||||
enum mpcc_movable_cm_location mcm_location;
|
||||
#endif /* TRIM_CM2 */
|
||||
struct dc_plane_cm cm;
|
||||
|
||||
struct dc_transfer_func *gamcor_tf;
|
||||
@@ -1739,7 +1756,7 @@ struct dc_plane_state {
|
||||
bool adaptive_sharpness_en;
|
||||
int adaptive_sharpness_policy;
|
||||
unsigned int sharpness_level;
|
||||
enum linear_light_scaling linear_light_scaling;
|
||||
enum dc_scaling_linearity scaling_linearity;
|
||||
unsigned int sdr_white_level_nits;
|
||||
struct cm_hist_control cm_hist_control;
|
||||
struct spl_sharpness_range sharpness_range;
|
||||
@@ -1763,6 +1780,7 @@ struct dc_plane_info {
|
||||
bool input_csc_enabled;
|
||||
unsigned int layer_index;
|
||||
enum chroma_cositing cositing;
|
||||
enum dc_scaling_linearity scaling_linearity;
|
||||
};
|
||||
|
||||
#include "dc_stream.h"
|
||||
@@ -1970,6 +1988,7 @@ struct dc_scratch_space {
|
||||
// BW ALLOCATON USB4 ONLY
|
||||
struct dc_dpia_bw_alloc dpia_bw_alloc_config;
|
||||
bool skip_implict_edp_power_control;
|
||||
bool forced_psr_active;
|
||||
enum backlight_control_type backlight_control_type;
|
||||
};
|
||||
|
||||
|
||||
@@ -2431,3 +2431,47 @@ void dc_dmub_srv_log_preos_dmcub_info(struct dc_dmub_srv *dc_dmub_srv)
|
||||
DC_LOG_DEBUG("fb_offset : 0x%016llx", dmub->preos_info.fb_offset);
|
||||
}
|
||||
}
|
||||
|
||||
bool dc_dmub_srv_ihc_set_dig_hdcp_interrupt_dest(
|
||||
struct dc_dmub_srv *dc_dmub_srv,
|
||||
uint8_t dig_id,
|
||||
bool to_dmu)
|
||||
{
|
||||
union dmub_rb_cmd cmd;
|
||||
|
||||
if (!dc_dmub_srv || !dc_dmub_srv->dmub)
|
||||
return false;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
cmd.ihc.header.type = DMUB_CMD__IHC;
|
||||
cmd.ihc.header.sub_type = DMUB_CMD__IHC_SET_DIG_HDCP_INTERRUPT_DEST;
|
||||
cmd.ihc.header.payload_bytes = sizeof(cmd.ihc.data);
|
||||
|
||||
cmd.ihc.data.dig_id = dig_id;
|
||||
cmd.ihc.data.to_dmu = to_dmu ? 1 : 0;
|
||||
|
||||
dc_wake_and_execute_dmub_cmd(dc_dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dc_dmub_srv_get_fams2_debug_meta(struct dc_dmub_srv *dc_dmub_srv)
|
||||
{
|
||||
union dmub_rb_cmd cmd;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
cmd.ib_fams2_debug_meta.header.type = DMUB_CMD__FW_ASSISTED_MCLK_SWITCH;
|
||||
cmd.ib_fams2_debug_meta.header.sub_type = DMUB_CMD__FAMS2_IB_DEBUG_META;
|
||||
|
||||
cmd.ib_fams2_debug_meta.ib_data.src.quad_part = dc_dmub_srv->dmub->ib_mem_gart.gpu_addr;
|
||||
cmd.ib_fams2_debug_meta.ib_data.size = dc_dmub_srv->dmub->ib_mem_gart.size > 0xFFFF ?
|
||||
0xFFFF : (uint16_t)dc_dmub_srv->dmub->ib_mem_gart.size;
|
||||
|
||||
/* flush any existing writes to the buffer to prevent conflicts */
|
||||
dmub_srv_flush_buffer_mem(dc_dmub_srv->dmub, &dc_dmub_srv->dmub->ib_mem_gart);
|
||||
|
||||
dm_execute_dmub_cmd_list(dc_dmub_srv->ctx, 1, &cmd, DM_DMUB_WAIT_TYPE_WAIT);
|
||||
|
||||
}
|
||||
|
||||
@@ -401,4 +401,27 @@ void dc_dmub_srv_release_hw(const struct dc *dc);
|
||||
* @dc - pointer to DC object
|
||||
*/
|
||||
void dc_dmub_srv_log_preos_dmcub_info(struct dc_dmub_srv *dc_dmub_srv);
|
||||
|
||||
/**
|
||||
* dc_dmub_srv_ihc_set_dig_hdcp_interrupt_dest() - Configure IHC interrupt destination.
|
||||
* @dc_dmub_srv: DMUB service handle
|
||||
* @dig_id: DIG engine ID (0-3)
|
||||
* @to_dmu: Route interrupt to DMU (true) or not (false)
|
||||
*
|
||||
* Sends command to DMUB firmware to configure IHC interrupt routing
|
||||
* for HDCP I2C transfer requests.
|
||||
*
|
||||
* Return: true on success, false on failure
|
||||
*/
|
||||
bool dc_dmub_srv_ihc_set_dig_hdcp_interrupt_dest(
|
||||
struct dc_dmub_srv *dc_dmub_srv,
|
||||
uint8_t dig_id,
|
||||
bool to_dmu);
|
||||
|
||||
/**
|
||||
* dc_dmub_srv_get_fams2_debug_meta() - Queries for FAMS2 debug metadata from DMUB and logs it.
|
||||
*
|
||||
* @dc_dmub_srv - pointer to DMUB service object
|
||||
*/
|
||||
void dc_dmub_srv_get_fams2_debug_meta(struct dc_dmub_srv *dc_dmub_srv);
|
||||
#endif /* _DMUB_DC_SRV_H_ */
|
||||
|
||||
@@ -530,6 +530,8 @@ char *dce_version_to_string(const int version)
|
||||
return "DCN 4.2";
|
||||
case DCN_VERSION_4_2B:
|
||||
return "DCN 4.2B";
|
||||
case DCN_VERSION_6_0:
|
||||
return "DCN 6.0";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@@ -205,9 +205,32 @@ enum surface_pixel_format {
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb,
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr,
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb,
|
||||
/* Planar 422 Formats*/
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P208, // 8 bpc
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P208, // 8 bpc
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P210, // 10 bpc
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P210, // 10 bpc
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P212, // 12 bpc
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P212, // 12 bpc
|
||||
SURFACE_PIXEL_FORMAT_SUBSAMPLE_END,
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_ACrYCb2101010 =
|
||||
SURFACE_PIXEL_FORMAT_SUBSAMPLE_END,
|
||||
/* packed 422 formats, they should reside here as the necessity for programming chroma parameters are determined wrt SURFACE_PIXEL_FORMAT_SUBSAMPLE_END*/
|
||||
/* Packed 422 Format, 8bpc*/
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_YCrYCb,
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_YCbYCr,
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_CrYCbY,
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_CbYCrY,
|
||||
/* Packed 422 Format, 10bpc*/
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_YCrYCb,
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_YCbYCr,
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_CrYCbY,
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_CbYCrY,
|
||||
/* Packed 422 Format, 12bpc*/
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_YCrYCb,
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_YCbYCr,
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_CrYCbY,
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_CbYCrY,
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_CrYCbA1010102,
|
||||
SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888,
|
||||
SURFACE_PIXEL_FORMAT_INVALID
|
||||
@@ -230,13 +253,19 @@ enum dc_pixel_format {
|
||||
/*video*/
|
||||
PIXEL_FORMAT_420BPP8,
|
||||
PIXEL_FORMAT_420BPP10,
|
||||
// Align with SPL formats
|
||||
PIXEL_FORMAT_422BPP8,
|
||||
PIXEL_FORMAT_422BPP10,
|
||||
PIXEL_FORMAT_422BPP12,
|
||||
PIXEL_FORMAT_444BPP8,
|
||||
PIXEL_FORMAT_444BPP10,
|
||||
/*end of pixel format definition*/
|
||||
PIXEL_FORMAT_INVALID,
|
||||
|
||||
PIXEL_FORMAT_GRPH_BEGIN = PIXEL_FORMAT_INDEX8,
|
||||
PIXEL_FORMAT_GRPH_END = PIXEL_FORMAT_FP16,
|
||||
PIXEL_FORMAT_VIDEO_BEGIN = PIXEL_FORMAT_420BPP8,
|
||||
PIXEL_FORMAT_VIDEO_END = PIXEL_FORMAT_420BPP10,
|
||||
PIXEL_FORMAT_VIDEO_END = PIXEL_FORMAT_444BPP10,
|
||||
PIXEL_FORMAT_UNKNOWN
|
||||
};
|
||||
|
||||
@@ -651,6 +680,7 @@ struct dc_cursor_attributes {
|
||||
enum dc_rotation_angle rotation_angle;
|
||||
|
||||
union dc_cursor_attribute_flags attribute_flags;
|
||||
bool force_cursor_to_disp_pref;
|
||||
};
|
||||
|
||||
struct dpp_cursor_attributes {
|
||||
@@ -1249,5 +1279,26 @@ struct cm_hist {
|
||||
uint32_t ch2[256];
|
||||
uint32_t ch3[256];
|
||||
};
|
||||
|
||||
enum pregam_mode {
|
||||
PREGAM_BYPASS = 0,
|
||||
PREGAM_DEGAM,
|
||||
PREGAM_REGAM
|
||||
};
|
||||
|
||||
enum degam_lut {
|
||||
DEGAM_SRGB = 0,
|
||||
DEGAM_GAMMA_22,
|
||||
DEGAM_GAMMA_24,
|
||||
DEGAM_GAMMA_26,
|
||||
DEGAM_BT2020,
|
||||
DEGAM_BT2100PQ,
|
||||
DEGAM_BT2100HLG
|
||||
};
|
||||
|
||||
enum regam_lut {
|
||||
REGAM_20 = 0,
|
||||
REGAM_24
|
||||
};
|
||||
#endif /* DC_HW_TYPES_H */
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ static struct spl_callbacks dcn32_spl_callbacks = {
|
||||
static struct spl_callbacks dcn401_spl_callbacks = {
|
||||
.spl_calc_lb_num_partitions = dscl401_spl_calc_lb_num_partitions,
|
||||
};
|
||||
static struct spl_callbacks dcn50_spl_callbacks = {
|
||||
.spl_calc_lb_num_partitions = dscl401_spl_calc_lb_num_partitions,
|
||||
};
|
||||
static void populate_splrect_from_rect(struct spl_rect *spl_rect, const struct rect *rect)
|
||||
{
|
||||
spl_rect->x = rect->x;
|
||||
@@ -71,6 +74,23 @@ static void populate_splformat_from_format(enum spl_pixel_format *spl_pixel_form
|
||||
else
|
||||
*spl_pixel_format = SPL_PIXEL_FORMAT_INVALID;
|
||||
}
|
||||
static void set_linear_light_scaling_preference(const struct dc_plane_state *plane_state, struct spl_in *spl_in)
|
||||
{
|
||||
if (plane_state != NULL) {
|
||||
switch (plane_state->scaling_linearity) {
|
||||
case DC_SCALING_LINEARITY_LINEAR:
|
||||
spl_in->lls_pref = LLS_PREF_YES;
|
||||
break;
|
||||
case DC_SCALING_LINEARITY_SOURCE:
|
||||
spl_in->lls_pref = LLS_PREF_NO;
|
||||
break;
|
||||
default:
|
||||
spl_in->lls_pref = LLS_PREF_DONT_CARE;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
spl_in->lls_pref = LLS_PREF_DONT_CARE;
|
||||
}
|
||||
/// @brief Translate SPL input parameters from pipe context
|
||||
/// @param pipe_ctx
|
||||
/// @param spl_in
|
||||
@@ -94,6 +114,9 @@ void translate_SPL_in_params_from_pipe_ctx(struct pipe_ctx *pipe_ctx, struct spl
|
||||
case DCN_VERSION_4_2B:
|
||||
spl_in->callbacks = dcn401_spl_callbacks;
|
||||
break;
|
||||
case DCN_VERSION_6_0:
|
||||
spl_in->callbacks = dcn50_spl_callbacks;
|
||||
break;
|
||||
default:
|
||||
spl_in->callbacks = dcn2_spl_callbacks;
|
||||
}
|
||||
@@ -189,7 +212,14 @@ void translate_SPL_in_params_from_pipe_ctx(struct pipe_ctx *pipe_ctx, struct spl
|
||||
if (pipe_ctx->stream->ctx->dc->debug.force_lls > 0)
|
||||
spl_in->lls_pref = pipe_ctx->stream->ctx->dc->debug.force_lls;
|
||||
else
|
||||
spl_in->lls_pref = plane_state->linear_light_scaling;
|
||||
if ((plane_state->ctx->dce_version == DCN_VERSION_4_01) ||
|
||||
(plane_state->ctx->dce_version == DCN_VERSION_4_2) ||
|
||||
(plane_state->ctx->dce_version == DCN_VERSION_4_2B))
|
||||
spl_in->lls_pref = LLS_PREF_DONT_CARE;
|
||||
else
|
||||
set_linear_light_scaling_preference(plane_state, spl_in);
|
||||
/* Translate upsampling mode*/
|
||||
spl_in->upsp_mode = pipe_ctx->plane_res.scl_data.upsp;
|
||||
/* Translate chroma subsampling offset ( cositing ) */
|
||||
if (pipe_ctx->stream->ctx->dc->debug.force_cositing)
|
||||
spl_in->basic_in.cositing = pipe_ctx->stream->ctx->dc->debug.force_cositing - 1;
|
||||
|
||||
@@ -125,4 +125,5 @@ bool dc_state_can_clear_stream_cursor_subvp_limit(const struct dc_stream_state *
|
||||
|
||||
bool dc_state_is_subvp_in_use(struct dc_state *state);
|
||||
|
||||
bool dc_state_is_alt_in_use(const struct dc *dc, const struct dc_state *state);
|
||||
#endif /* _DC_STATE_PRIV_H_ */
|
||||
|
||||
@@ -329,6 +329,9 @@ struct dc_stream_state {
|
||||
|
||||
enum dc_drr_trigger_mode drr_trigger_mode;
|
||||
|
||||
|
||||
enum dc_blending_linearity blending_linearity;
|
||||
struct dc_update_scratch_space *update_scratch;
|
||||
bool firmware_controlled_hdr_info_packet;
|
||||
};
|
||||
|
||||
@@ -380,6 +383,8 @@ struct dc_stream_update {
|
||||
bool *scaler_sharpener_update;
|
||||
bool *sharpening_required;
|
||||
|
||||
enum dc_blending_linearity *blending_linearity;
|
||||
|
||||
enum dc_drr_trigger_mode *drr_trigger_mode;
|
||||
};
|
||||
|
||||
|
||||
@@ -389,6 +389,16 @@ struct dc_csc_adjustments {
|
||||
struct fixed31_32 hue;
|
||||
};
|
||||
|
||||
enum dc_scaling_linearity {
|
||||
DC_SCALING_LINEARITY_LINEAR,
|
||||
DC_SCALING_LINEARITY_SOURCE,
|
||||
};
|
||||
|
||||
enum dc_blending_linearity {
|
||||
DC_BLENDING_LINEARITY_LINEAR,
|
||||
DC_BLENDING_LINEARITY_SOURCE,
|
||||
};
|
||||
|
||||
/* Scaling format */
|
||||
enum scaling_transformation {
|
||||
SCALING_TRANSFORMATION_UNINITIALIZED,
|
||||
@@ -1035,9 +1045,10 @@ enum backlight_control_type {
|
||||
BACKLIGHT_CONTROL_AMD_AUX = 2,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
|
||||
#define MAX_CRC_WINDOW_NUM 2
|
||||
|
||||
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
|
||||
|
||||
struct otg_phy_mux {
|
||||
uint8_t phy_output_num;
|
||||
uint8_t otg_output_num;
|
||||
|
||||
@@ -109,4 +109,12 @@ DCCG_DCN42 = dcn42_dccg.o
|
||||
AMD_DAL_DCCG_DCN42 = $(addprefix $(AMDDALPATH)/dc/dccg/dcn42/,$(DCCG_DCN42))
|
||||
|
||||
AMD_DISPLAY_FILES += $(AMD_DAL_DCCG_DCN42)
|
||||
###############################################################################
|
||||
# DCN60
|
||||
###############################################################################
|
||||
DCCG_DCN60 = dcn60_dccg.o
|
||||
|
||||
AMD_DAL_DCCG_DCN60 = $(addprefix $(AMDDALPATH)/dc/dccg/dcn60/,$(DCCG_DCN60))
|
||||
|
||||
AMD_DISPLAY_FILES += $(AMD_DAL_DCCG_DCN60)
|
||||
endif
|
||||
|
||||
@@ -377,6 +377,13 @@
|
||||
type OTG3_DROP_PIXEL;\
|
||||
type RESYNC_FIFO_LEVEL_ADJUST_EN;
|
||||
|
||||
#define DCCG60_REG_FIELD_LIST(type) \
|
||||
type OTG_ADD_DROP_PIXEL_DONE;\
|
||||
type DSCCLK0_SRC_SEL;\
|
||||
type DSCCLK1_SRC_SEL;\
|
||||
type DSCCLK2_SRC_SEL;\
|
||||
type DSCCLK3_SRC_SEL;
|
||||
|
||||
struct dccg_shift {
|
||||
DCCG_REG_FIELD_LIST(uint8_t)
|
||||
DCCG3_REG_FIELD_LIST(uint8_t)
|
||||
@@ -386,6 +393,7 @@ struct dccg_shift {
|
||||
DCCG35_REG_FIELD_LIST(uint8_t)
|
||||
DCCG401_REG_FIELD_LIST(uint8_t)
|
||||
DCCG42_REG_FIELD_LIST(uint8_t)
|
||||
DCCG60_REG_FIELD_LIST(uint8_t)
|
||||
};
|
||||
|
||||
struct dccg_mask {
|
||||
@@ -397,6 +405,7 @@ struct dccg_mask {
|
||||
DCCG35_REG_FIELD_LIST(uint32_t)
|
||||
DCCG401_REG_FIELD_LIST(uint32_t)
|
||||
DCCG42_REG_FIELD_LIST(uint32_t)
|
||||
DCCG60_REG_FIELD_LIST(uint32_t)
|
||||
};
|
||||
|
||||
#define DCCG_REG_VARIABLE_LIST \
|
||||
@@ -511,6 +520,7 @@ struct dccg_mask {
|
||||
struct dccg_registers {
|
||||
DCCG_REG_VARIABLE_LIST;
|
||||
uint32_t OTG_ADD_DROP_PIXEL_CNTL;
|
||||
uint32_t DSCCLK_SRC_SEL;
|
||||
};
|
||||
|
||||
struct dcn_dccg {
|
||||
|
||||
187
drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c
Normal file
187
drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.c
Normal file
@@ -0,0 +1,187 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright 2025 Advanced Micro Devices, Inc.
|
||||
|
||||
#include "reg_helper.h"
|
||||
#include "core_types.h"
|
||||
#include "dcn42/dcn42_dccg.h"
|
||||
#include "dcn60_dccg.h"
|
||||
|
||||
#define TO_DCN_DCCG(dccg)\
|
||||
container_of(dccg, struct dcn_dccg, base)
|
||||
|
||||
#define REG(reg) \
|
||||
(dccg_dcn->regs->reg)
|
||||
|
||||
#undef FN
|
||||
#define FN(reg_name, field_name) \
|
||||
dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name
|
||||
|
||||
#define CTX \
|
||||
dccg_dcn->base.ctx
|
||||
#define DC_LOGGER \
|
||||
dccg->ctx->logger
|
||||
|
||||
static void dccg60_set_pixel_rate_div(
|
||||
struct dccg *dccg,
|
||||
uint32_t otg_inst,
|
||||
enum pixel_rate_div tmds_div,
|
||||
enum pixel_rate_div unused)
|
||||
{
|
||||
(void)unused;
|
||||
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
|
||||
uint32_t cur_tmds_div = PIXEL_RATE_DIV_NA;
|
||||
uint32_t dp_dto_int;
|
||||
uint32_t reg_val;
|
||||
|
||||
// only 2 is valid on dcn401
|
||||
if (tmds_div != PIXEL_RATE_DIV_BY_2 && tmds_div != PIXEL_RATE_DIV_BY_4) {
|
||||
return;
|
||||
}
|
||||
|
||||
dccg401_get_pixel_rate_div(dccg, otg_inst, &cur_tmds_div, &dp_dto_int);
|
||||
if (tmds_div == cur_tmds_div)
|
||||
return;
|
||||
|
||||
// encode enum to register value
|
||||
reg_val = tmds_div == PIXEL_RATE_DIV_BY_4 ? 1 : 0;
|
||||
|
||||
switch (otg_inst) {
|
||||
case 0:
|
||||
REG_UPDATE(OTG_PIXEL_RATE_DIV,
|
||||
OTG0_TMDS_PIXEL_RATE_DIV, reg_val);
|
||||
break;
|
||||
case 1:
|
||||
REG_UPDATE(OTG_PIXEL_RATE_DIV,
|
||||
OTG1_TMDS_PIXEL_RATE_DIV, reg_val);
|
||||
break;
|
||||
case 2:
|
||||
REG_UPDATE(OTG_PIXEL_RATE_DIV,
|
||||
OTG2_TMDS_PIXEL_RATE_DIV, reg_val);
|
||||
break;
|
||||
case 3:
|
||||
REG_UPDATE(OTG_PIXEL_RATE_DIV,
|
||||
OTG3_TMDS_PIXEL_RATE_DIV, reg_val);
|
||||
break;
|
||||
default:
|
||||
BREAK_TO_DEBUGGER();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void dccg60_set_dto_dscclk(struct dccg *dccg, uint32_t inst,
|
||||
uint32_t num_slices_h)
|
||||
{
|
||||
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
|
||||
|
||||
switch (inst) {
|
||||
case 0:
|
||||
REG_UPDATE_2(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_PHASE, 1,
|
||||
DSCCLK0_DTO_MODULO, 1);
|
||||
REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_EN, 1);
|
||||
|
||||
/*
|
||||
* Source for dscclk should be set when dto tuned clock is used.
|
||||
* For 1 slice config, set src to dprefclk.
|
||||
* For 2 or more slice config, set src to dispclk.
|
||||
*/
|
||||
if (num_slices_h == 1)
|
||||
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK0_SRC_SEL, 1);
|
||||
else
|
||||
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK0_SRC_SEL, 0);
|
||||
|
||||
break;
|
||||
case 1:
|
||||
REG_UPDATE_2(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_PHASE, 1,
|
||||
DSCCLK1_DTO_MODULO, 1);
|
||||
REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1);
|
||||
|
||||
if (num_slices_h == 1)
|
||||
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK1_SRC_SEL, 1);
|
||||
else
|
||||
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK1_SRC_SEL, 0);
|
||||
|
||||
break;
|
||||
case 2:
|
||||
REG_UPDATE_2(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_PHASE, 1,
|
||||
DSCCLK2_DTO_MODULO, 1);
|
||||
REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1);
|
||||
|
||||
if (num_slices_h == 1)
|
||||
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK2_SRC_SEL, 1);
|
||||
else
|
||||
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK2_SRC_SEL, 0);
|
||||
|
||||
break;
|
||||
case 3:
|
||||
REG_UPDATE_2(DSCCLK3_DTO_PARAM, DSCCLK3_DTO_PHASE, 1,
|
||||
DSCCLK3_DTO_MODULO, 1);
|
||||
REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_EN, 1);
|
||||
|
||||
if (num_slices_h == 1)
|
||||
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK3_SRC_SEL, 1);
|
||||
else
|
||||
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK3_SRC_SEL, 0);
|
||||
|
||||
break;
|
||||
default:
|
||||
BREAK_TO_DEBUGGER();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct dccg_funcs dccg60_funcs = {
|
||||
.enable_hdmicharclk = dccg401_enable_hdmicharclk,
|
||||
.disable_hdmicharclk = dccg401_disable_hdmicharclk,
|
||||
.set_hdmistreamclk = dccg401_set_hdmistreamclk,
|
||||
.update_dpp_dto = dccg401_update_dpp_dto,
|
||||
.get_dccg_ref_freq = dccg401_get_dccg_ref_freq,
|
||||
.dccg_init = dccg401_init,
|
||||
.set_dpstreamclk = dccg401_set_dpstreamclk,
|
||||
.enable_symclk32_se = dccg31_enable_symclk32_se,
|
||||
.disable_symclk32_se = dccg31_disable_symclk32_se,
|
||||
.enable_symclk32_le = dccg401_enable_symclk32_le,
|
||||
.disable_symclk32_le = dccg401_disable_symclk32_le,
|
||||
.set_physymclk = dccg401_set_physymclk,
|
||||
.set_dtbclk_dto = NULL,
|
||||
.set_dto_dscclk = dccg60_set_dto_dscclk,
|
||||
.set_ref_dscclk = dccg401_set_ref_dscclk,
|
||||
.set_valid_pixel_rate = NULL,
|
||||
.set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en,
|
||||
.set_audio_dtbclk_dto = NULL,
|
||||
.otg_add_pixel = dccg42_otg_add_pixel,
|
||||
.otg_drop_pixel = dccg42_otg_drop_pixel,
|
||||
.set_pixel_rate_div = dccg60_set_pixel_rate_div,
|
||||
.get_pixel_rate_div = dccg401_get_pixel_rate_div,
|
||||
.set_dp_dto = dccg401_set_dp_dto,
|
||||
.enable_symclk_se = dccg401_enable_symclk_se,
|
||||
.disable_symclk_se = dccg401_disable_symclk_se,
|
||||
.set_dtbclk_p_src = dccg401_set_dtbclk_p_src,
|
||||
.dccg_read_reg_state = dccg31_read_reg_state,
|
||||
.allow_clock_gating = dccg2_allow_clock_gating
|
||||
};
|
||||
|
||||
struct dccg *dccg60_create(
|
||||
struct dc_context *ctx,
|
||||
const struct dccg_registers *regs,
|
||||
const struct dccg_shift *dccg_shift,
|
||||
const struct dccg_mask *dccg_mask)
|
||||
{
|
||||
struct dcn_dccg *dccg_dcn = kzalloc(sizeof(*dccg_dcn), GFP_KERNEL);
|
||||
struct dccg *base;
|
||||
|
||||
if (dccg_dcn == NULL) {
|
||||
BREAK_TO_DEBUGGER();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
base = &dccg_dcn->base;
|
||||
base->ctx = ctx;
|
||||
base->funcs = &dccg60_funcs;
|
||||
|
||||
dccg_dcn->regs = regs;
|
||||
dccg_dcn->dccg_shift = dccg_shift;
|
||||
dccg_dcn->dccg_mask = dccg_mask;
|
||||
|
||||
return &dccg_dcn->base;
|
||||
}
|
||||
182
drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.h
Normal file
182
drivers/gpu/drm/amd/display/dc/dccg/dcn60/dcn60_dccg.h
Normal file
@@ -0,0 +1,182 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright 2025 Advanced Micro Devices, Inc.
|
||||
|
||||
#ifndef __DCN60_DCCG_H__
|
||||
#define __DCN60_DCCG_H__
|
||||
|
||||
#include "dcn401/dcn401_dccg.h"
|
||||
|
||||
#define DCCG_MASK_SH_LIST_DCN60(mask_sh) \
|
||||
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 0, mask_sh),\
|
||||
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 1, mask_sh),\
|
||||
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 2, mask_sh),\
|
||||
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 3, mask_sh),\
|
||||
DCCG_SF(DPPCLK_CTRL, DPPCLK0_EN, mask_sh),\
|
||||
DCCG_SF(DPPCLK_CTRL, DPPCLK1_EN, mask_sh),\
|
||||
DCCG_SF(DPPCLK_CTRL, DPPCLK2_EN, mask_sh),\
|
||||
DCCG_SF(DPPCLK_CTRL, DPPCLK3_EN, mask_sh),\
|
||||
DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_PHASE, mask_sh),\
|
||||
DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_MODULO, mask_sh),\
|
||||
DCCG_SF(HDMICHARCLK0_CLOCK_CNTL, HDMICHARCLK0_EN, mask_sh),\
|
||||
DCCG_SF(HDMICHARCLK0_CLOCK_CNTL, HDMICHARCLK0_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(PHYASYMCLK_CLOCK_CNTL, PHYASYMCLK_EN, mask_sh),\
|
||||
DCCG_SF(PHYASYMCLK_CLOCK_CNTL, PHYASYMCLK_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_EN, mask_sh),\
|
||||
DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_EN, mask_sh),\
|
||||
DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(PHYDSYMCLK_CLOCK_CNTL, PHYDSYMCLK_EN, mask_sh),\
|
||||
DCCG_SF(PHYDSYMCLK_CLOCK_CNTL, PHYDSYMCLK_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK0_EN, mask_sh),\
|
||||
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK1_EN, mask_sh),\
|
||||
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK2_EN, mask_sh),\
|
||||
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK3_EN, mask_sh),\
|
||||
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK0_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK1_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK2_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK3_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(HDMISTREAMCLK_CNTL, HDMISTREAMCLK0_EN, mask_sh),\
|
||||
DCCG_SF(HDMISTREAMCLK_CNTL, HDMISTREAMCLK0_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE0_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE1_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE2_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE3_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE0_EN, mask_sh),\
|
||||
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE1_EN, mask_sh),\
|
||||
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE2_EN, mask_sh),\
|
||||
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE3_EN, mask_sh),\
|
||||
DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE0_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE1_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE0_EN, mask_sh),\
|
||||
DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE1_EN, mask_sh),\
|
||||
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 0, mask_sh),\
|
||||
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 1, mask_sh),\
|
||||
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 2, mask_sh),\
|
||||
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 3, mask_sh),\
|
||||
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG0_ADD_PIXEL, mask_sh),\
|
||||
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG1_ADD_PIXEL, mask_sh),\
|
||||
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG2_ADD_PIXEL, mask_sh),\
|
||||
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG3_ADD_PIXEL, mask_sh),\
|
||||
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG0_DROP_PIXEL, mask_sh),\
|
||||
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG1_DROP_PIXEL, mask_sh),\
|
||||
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG2_DROP_PIXEL, mask_sh),\
|
||||
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG3_DROP_PIXEL, mask_sh),\
|
||||
DCCG_SF(OTG_PIXEL_RATE_DIV, OTG0_TMDS_PIXEL_RATE_DIV, mask_sh),\
|
||||
DCCG_SF(OTG_PIXEL_RATE_DIV, DPDTO0_INT, mask_sh),\
|
||||
DCCG_SF(OTG_PIXEL_RATE_DIV, OTG1_TMDS_PIXEL_RATE_DIV, mask_sh),\
|
||||
DCCG_SF(OTG_PIXEL_RATE_DIV, DPDTO1_INT, mask_sh),\
|
||||
DCCG_SF(OTG_PIXEL_RATE_DIV, OTG2_TMDS_PIXEL_RATE_DIV, mask_sh),\
|
||||
DCCG_SF(OTG_PIXEL_RATE_DIV, DPDTO2_INT, mask_sh),\
|
||||
DCCG_SF(OTG_PIXEL_RATE_DIV, OTG3_TMDS_PIXEL_RATE_DIV, mask_sh),\
|
||||
DCCG_SF(OTG_PIXEL_RATE_DIV, DPDTO3_INT, mask_sh),\
|
||||
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P0_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P0_EN, mask_sh),\
|
||||
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P1_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P1_EN, mask_sh),\
|
||||
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P2_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P2_EN, mask_sh),\
|
||||
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P3_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P3_EN, mask_sh),\
|
||||
DCCG_SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO_SEL, mask_sh),\
|
||||
DCCG_SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYASYMCLK_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYBSYMCLK_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYCSYMCLK_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYDSYMCLK_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SFII(OTG, PIXEL_RATE_CNTL, DP_DTO, ENABLE, 0, mask_sh),\
|
||||
DCCG_SFII(OTG, PIXEL_RATE_CNTL, DP_DTO, ENABLE, 1, mask_sh),\
|
||||
DCCG_SFII(OTG, PIXEL_RATE_CNTL, DP_DTO, ENABLE, 2, mask_sh),\
|
||||
DCCG_SFII(OTG, PIXEL_RATE_CNTL, DP_DTO, ENABLE, 3, mask_sh),\
|
||||
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 0, mask_sh),\
|
||||
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 1, mask_sh),\
|
||||
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 2, mask_sh),\
|
||||
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 3, mask_sh),\
|
||||
DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK0_EN, mask_sh),\
|
||||
DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK1_EN, mask_sh),\
|
||||
DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK2_EN, mask_sh),\
|
||||
DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK3_EN, mask_sh),\
|
||||
DCCG_SF(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_PHASE, mask_sh),\
|
||||
DCCG_SF(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_MODULO, mask_sh),\
|
||||
DCCG_SF(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_PHASE, mask_sh),\
|
||||
DCCG_SF(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_MODULO, mask_sh),\
|
||||
DCCG_SF(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_PHASE, mask_sh),\
|
||||
DCCG_SF(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_MODULO, mask_sh),\
|
||||
DCCG_SF(DSCCLK3_DTO_PARAM, DSCCLK3_DTO_PHASE, mask_sh),\
|
||||
DCCG_SF(DSCCLK3_DTO_PARAM, DSCCLK3_DTO_MODULO, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL2, HDMICHARCLK0_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, HDMISTREAMCLK0_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE0_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE1_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE2_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE3_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE0_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE1_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE2_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE3_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE0_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE1_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE2_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE3_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE0_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE1_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE2_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE3_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL4, HDMICHARCLK0_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYA_REFCLK_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYB_REFCLK_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYC_REFCLK_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYD_REFCLK_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKA_FE_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKB_FE_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKC_FE_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_FE_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKA_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKB_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKC_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK0_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK1_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK2_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK0_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK1_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK2_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, HDMISTREAMCLK0_ROOT_GATE_DISABLE, mask_sh),\
|
||||
DCCG_SF(SYMCLKA_CLOCK_ENABLE, SYMCLKA_CLOCK_ENABLE, mask_sh),\
|
||||
DCCG_SF(SYMCLKB_CLOCK_ENABLE, SYMCLKB_CLOCK_ENABLE, mask_sh),\
|
||||
DCCG_SF(SYMCLKC_CLOCK_ENABLE, SYMCLKC_CLOCK_ENABLE, mask_sh),\
|
||||
DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_CLOCK_ENABLE, mask_sh),\
|
||||
DCCG_SF(SYMCLKA_CLOCK_ENABLE, SYMCLKA_FE_EN, mask_sh),\
|
||||
DCCG_SF(SYMCLKB_CLOCK_ENABLE, SYMCLKB_FE_EN, mask_sh),\
|
||||
DCCG_SF(SYMCLKC_CLOCK_ENABLE, SYMCLKC_FE_EN, mask_sh),\
|
||||
DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_FE_EN, mask_sh),\
|
||||
DCCG_SF(SYMCLKA_CLOCK_ENABLE, SYMCLKA_FE_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(SYMCLKB_CLOCK_ENABLE, SYMCLKB_FE_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(SYMCLKC_CLOCK_ENABLE, SYMCLKC_FE_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_FE_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(DSCCLK_SRC_SEL, DSCCLK0_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(DSCCLK_SRC_SEL, DSCCLK1_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(DSCCLK_SRC_SEL, DSCCLK2_SRC_SEL, mask_sh),\
|
||||
DCCG_SF(DSCCLK_SRC_SEL, DSCCLK3_SRC_SEL, mask_sh),\
|
||||
|
||||
struct dccg *dccg60_create(
|
||||
struct dc_context *ctx,
|
||||
const struct dccg_registers *regs,
|
||||
const struct dccg_shift *dccg_shift,
|
||||
const struct dccg_mask *dccg_mask);
|
||||
|
||||
#endif //__DCN60_DCCG_H__
|
||||
@@ -1117,6 +1117,10 @@ static bool dcn401_program_pix_clk(
|
||||
if (clock_source->ctx->dc->caps.is_apu &&
|
||||
pix_clk_params->requested_pix_clk_100hz &&
|
||||
dc_is_hdmi_frl_signal(pix_clk_params->signal_type)) {
|
||||
//make sure dtbclk is enabled
|
||||
if (clock_source->ctx->dc->clk_mgr->funcs->request_dtbclk)
|
||||
clock_source->ctx->dc->clk_mgr->funcs->request_dtbclk(
|
||||
clock_source->ctx->dc->clk_mgr, true);
|
||||
/*need hdmistreamclk before vpg block register access*/
|
||||
clock_source->ctx->dc->res_pool->dccg->funcs->set_hdmistreamclk(
|
||||
clock_source->ctx->dc->res_pool->dccg,
|
||||
@@ -1493,6 +1497,13 @@ static const struct clock_source_funcs dcn401_clk_src_funcs = {
|
||||
.get_dp_dto_frequency_100hz = dcn401_get_dp_dto_frequency_100hz
|
||||
};
|
||||
|
||||
static const struct clock_source_funcs dcn50_clk_src_funcs = {
|
||||
.cs_power_down = dce110_clock_source_power_down,
|
||||
.program_pix_clk = dcn401_program_pix_clk,
|
||||
.get_pix_clk_dividers = dcn3_get_pix_clk_dividers,
|
||||
.get_dp_dto_frequency_100hz = dcn401_get_dp_dto_frequency_100hz
|
||||
};
|
||||
|
||||
/*****************************************/
|
||||
/* Constructor */
|
||||
/*****************************************/
|
||||
@@ -1922,6 +1933,23 @@ bool dcn401_clk_src_construct(
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool dcn50_clk_src_construct(
|
||||
struct dce110_clk_src *clk_src,
|
||||
struct dc_context *ctx,
|
||||
struct dc_bios *bios,
|
||||
enum clock_source_id id,
|
||||
const struct dce110_clk_src_regs *regs,
|
||||
const struct dce110_clk_src_shift *cs_shift,
|
||||
const struct dce110_clk_src_mask *cs_mask)
|
||||
{
|
||||
bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask);
|
||||
|
||||
clk_src->base.funcs = &dcn50_clk_src_funcs;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool dcn301_clk_src_construct(
|
||||
struct dce110_clk_src *clk_src,
|
||||
struct dc_context *ctx,
|
||||
|
||||
@@ -339,6 +339,15 @@ bool dcn401_clk_src_construct(
|
||||
const struct dce110_clk_src_regs *regs,
|
||||
const struct dce110_clk_src_shift *cs_shift,
|
||||
const struct dce110_clk_src_mask *cs_mask);
|
||||
bool dcn50_clk_src_construct(
|
||||
struct dce110_clk_src *clk_src,
|
||||
struct dc_context *ctx,
|
||||
struct dc_bios *bios,
|
||||
enum clock_source_id id,
|
||||
const struct dce110_clk_src_regs *regs,
|
||||
const struct dce110_clk_src_shift *cs_shift,
|
||||
const struct dce110_clk_src_mask *cs_mask);
|
||||
|
||||
/* this table is use to find *1.001 and /1.001 pixel rates from non-precise pixel rate */
|
||||
struct pixel_rate_range_table_entry {
|
||||
unsigned int range_min_khz;
|
||||
|
||||
@@ -132,4 +132,12 @@ DIO_DCN42 = dcn42_dio_link_encoder.o dcn42_dio_stream_encoder.o
|
||||
AMD_DAL_DIO_DCN42 = $(addprefix $(AMDDALPATH)/dc/dio/dcn42/,$(DIO_DCN42))
|
||||
|
||||
AMD_DISPLAY_FILES += $(AMD_DAL_DIO_DCN42)
|
||||
###############################################################################
|
||||
# DCN60
|
||||
###############################################################################
|
||||
DIO_DCN60 = dcn60_dio_link_encoder.o dcn60_dio_stream_encoder.o
|
||||
|
||||
AMD_DAL_DIO_DCN60 = $(addprefix $(AMDDALPATH)/dc/dio/dcn60/,$(DIO_DCN60))
|
||||
|
||||
AMD_DISPLAY_FILES += $(AMD_DAL_DIO_DCN60)
|
||||
endif
|
||||
|
||||
@@ -75,12 +75,14 @@ struct dcn10_link_enc_aux_registers {
|
||||
uint32_t AUX_DPHY_RX_CONTROL0;
|
||||
uint32_t AUX_DPHY_TX_CONTROL;
|
||||
uint32_t AUX_DPHY_RX_CONTROL1;
|
||||
uint32_t DC_GPIO_DDC;
|
||||
};
|
||||
|
||||
struct dcn10_link_enc_hpd_registers {
|
||||
uint32_t DC_HPD_CONTROL;
|
||||
uint32_t DC_HPD_INT_STATUS;
|
||||
uint32_t DC_HPD_TOGGLE_FILT_CNTL;
|
||||
uint32_t HPD_CTRL;
|
||||
};
|
||||
|
||||
struct dcn10_link_enc_registers {
|
||||
@@ -171,6 +173,8 @@ struct dcn10_link_enc_registers {
|
||||
uint32_t DIO_LINKF_CNTL;
|
||||
uint32_t DIO_CLK_CNTL;
|
||||
uint32_t DIG_BE_CLK_CNTL;
|
||||
uint32_t HDCP_I2C_CONTROL_0;
|
||||
uint32_t HDCP_INT_CONTROL;
|
||||
};
|
||||
|
||||
#define LE_SF(reg_name, field_name, post_fix)\
|
||||
@@ -508,12 +512,23 @@ struct dcn10_link_enc_registers {
|
||||
type SYMCLKF_G_HDCP_GATE_DIS;\
|
||||
type SYMCLKG_G_HDCP_GATE_DIS
|
||||
|
||||
#define DCN60_LINK_ENCODER_REG_FIELD_LIST(type) \
|
||||
type HDCP_I2C_DISABLE;\
|
||||
type HDCP_I2C_DDC_SELECT;\
|
||||
type HDCP_I2C_XFER_REQ_MASK;\
|
||||
type AUX_PAD1_MODE;\
|
||||
type HPD1_Y_POL_INVERT;\
|
||||
type HPD2_Y_POL_INVERT;\
|
||||
type HPD3_Y_POL_INVERT;\
|
||||
type HPD4_Y_POL_INVERT
|
||||
|
||||
struct dcn10_link_enc_shift {
|
||||
DCN_LINK_ENCODER_REG_FIELD_LIST(uint8_t);
|
||||
DCN20_LINK_ENCODER_REG_FIELD_LIST(uint8_t);
|
||||
DCN30_LINK_ENCODER_REG_FIELD_LIST(uint8_t);
|
||||
DCN31_LINK_ENCODER_REG_FIELD_LIST(uint8_t);
|
||||
DCN35_LINK_ENCODER_REG_FIELD_LIST(uint8_t);
|
||||
DCN60_LINK_ENCODER_REG_FIELD_LIST(uint8_t);
|
||||
};
|
||||
|
||||
struct dcn10_link_enc_mask {
|
||||
@@ -522,6 +537,7 @@ struct dcn10_link_enc_mask {
|
||||
DCN30_LINK_ENCODER_REG_FIELD_LIST(uint32_t);
|
||||
DCN31_LINK_ENCODER_REG_FIELD_LIST(uint32_t);
|
||||
DCN35_LINK_ENCODER_REG_FIELD_LIST(uint32_t);
|
||||
DCN60_LINK_ENCODER_REG_FIELD_LIST(uint32_t);
|
||||
};
|
||||
|
||||
struct dcn10_link_encoder {
|
||||
|
||||
@@ -384,6 +384,20 @@ enum signal_type dcn401_get_dig_mode(
|
||||
}
|
||||
}
|
||||
|
||||
void dcn401_setup_ri_pj_check_in_sw_or_hw_mode(
|
||||
struct link_encoder *enc,
|
||||
unsigned char aux_or_ddc_instance,
|
||||
bool enable_sw_mode)
|
||||
{
|
||||
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
|
||||
|
||||
REG_UPDATE_2(HDCP_I2C_CONTROL_0,
|
||||
HDCP_I2C_DISABLE, enable_sw_mode,
|
||||
HDCP_I2C_DDC_SELECT, aux_or_ddc_instance);
|
||||
|
||||
REG_UPDATE(HDCP_INT_CONTROL, HDCP_I2C_XFER_REQ_MASK, enable_sw_mode);
|
||||
}
|
||||
|
||||
static const struct link_encoder_funcs dcn401_link_enc_funcs = {
|
||||
.read_state = link_enc2_read_state,
|
||||
.validate_output_with_stream =
|
||||
@@ -423,6 +437,7 @@ static const struct link_encoder_funcs dcn401_link_enc_funcs = {
|
||||
.get_txffe = dpcs401_get_txffe,
|
||||
.set_txffe = dpcs401_set_txffe,
|
||||
.set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
|
||||
.setup_ri_pj_check_in_sw_or_hw_mode = dcn401_setup_ri_pj_check_in_sw_or_hw_mode,
|
||||
.get_hpd_state = dcn10_get_hpd_state,
|
||||
.program_hpd_filter = dcn10_program_hpd_filter,
|
||||
};
|
||||
|
||||
@@ -104,6 +104,11 @@
|
||||
LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN, mask_sh),\
|
||||
LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL1, AUX_RX_TIMEOUT_LEN_MUL, mask_sh)
|
||||
|
||||
#define LINK_ENCODER_MASK_SH_LIST_DCN60_ON_DCN401(mask_sh) \
|
||||
LE_SF(DIG0_HDCP_I2C_CONTROL_0, HDCP_I2C_DISABLE, mask_sh),\
|
||||
LE_SF(DIG0_HDCP_I2C_CONTROL_0, HDCP_I2C_DDC_SELECT, mask_sh),\
|
||||
LE_SF(DIG0_HDCP_INT_CONTROL, HDCP_I2C_XFER_REQ_MASK, mask_sh)
|
||||
|
||||
void dcn401_link_encoder_construct(
|
||||
struct dcn20_link_encoder *enc20,
|
||||
const struct encoder_init_data *init_data,
|
||||
@@ -147,4 +152,9 @@ enum signal_type dcn401_get_dig_mode(
|
||||
bool dcn401_is_dig_enabled(struct link_encoder *enc);
|
||||
|
||||
enum signal_type dcn401_get_dig_mode(struct link_encoder *enc);
|
||||
|
||||
void dcn401_setup_ri_pj_check_in_sw_or_hw_mode(
|
||||
struct link_encoder *enc,
|
||||
unsigned char aux_or_ddc_instance,
|
||||
bool enable_sw_mode);
|
||||
#endif /* __DC_LINK_ENCODER__DCN401_H__ */
|
||||
|
||||
@@ -0,0 +1,373 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright 2025 Advanced Micro Devices, Inc.
|
||||
|
||||
#include "reg_helper.h"
|
||||
|
||||
#include "core_types.h"
|
||||
#include "link_encoder.h"
|
||||
#include "dcn31/dcn31_dio_link_encoder.h"
|
||||
#include "dcn32/dcn32_dio_link_encoder.h"
|
||||
#include "dcn401/dcn401_dio_link_encoder.h"
|
||||
#include "dcn42/dcn42_dio_link_encoder.h"
|
||||
#include "dcn60_dio_link_encoder.h"
|
||||
#include "stream_encoder.h"
|
||||
#include "dc_bios_types.h"
|
||||
|
||||
#include "gpio_service_interface.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
||||
#endif
|
||||
|
||||
#define CTX \
|
||||
enc10->base.ctx
|
||||
#define DC_LOGGER \
|
||||
enc10->base.ctx->logger
|
||||
|
||||
#define REG(reg)\
|
||||
(enc10->link_regs->reg)
|
||||
|
||||
#undef FN
|
||||
#define FN(reg_name, field_name) \
|
||||
enc10->link_shift->field_name, enc10->link_mask->field_name
|
||||
|
||||
#define AUX_REG(reg)\
|
||||
(enc10->aux_regs->reg)
|
||||
|
||||
#define AUX_REG_READ(reg_name) \
|
||||
dm_read_reg(CTX, AUX_REG(reg_name))
|
||||
|
||||
#define AUX_REG_WRITE(reg_name, val) \
|
||||
dm_write_reg(CTX, AUX_REG(reg_name), val)
|
||||
|
||||
#define AUX_REG_UPDATE_N(reg_name, n, ...) \
|
||||
generic_reg_update_ex(CTX, \
|
||||
AUX_REG(reg_name), \
|
||||
n, __VA_ARGS__)
|
||||
|
||||
#define AUX_REG_UPDATE_1(reg_name, field, val) \
|
||||
AUX_REG_UPDATE_N(reg_name, 1, \
|
||||
FN(reg_name, field), val)
|
||||
|
||||
#define HPD_REG(reg)\
|
||||
(enc10->hpd_regs->reg)
|
||||
|
||||
#define HPD_REG_GET(reg_name, field, val) \
|
||||
generic_reg_get(CTX, HPD_REG(reg_name), \
|
||||
FN(reg_name, field), val)
|
||||
|
||||
#define HPD_REG_SET_N(reg_name, n, initial_val, ...) \
|
||||
generic_reg_set_ex(CTX, \
|
||||
HPD_REG(reg_name), \
|
||||
initial_val, \
|
||||
n, __VA_ARGS__)
|
||||
|
||||
#define HPD_REG_SET_2(reg, init_value, f1, v1, f2, v2) \
|
||||
HPD_REG_SET_N(reg, 2, init_value, \
|
||||
FN(reg, f1), v1,\
|
||||
FN(reg, f2), v2)
|
||||
|
||||
#define HPD_REG_SET_1(reg, init_value, f1, v1) \
|
||||
HPD_REG_SET_N(reg, 1, init_value, \
|
||||
FN(reg, f1), v1)
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
||||
#endif
|
||||
|
||||
// DP2/HDMI FRL PRESET_LEVEL EQ options for FFE byte
|
||||
// Preset level 0-32 bits[0:4]
|
||||
#define PRESET_LEVEL_BYTE__LEVEL__SHIFT 0x0u
|
||||
#define PRESET_LEVEL_BYTE__LEVEL__MASK 0x1Fu
|
||||
// Enable no preshoot bit[5]
|
||||
#define PRESET_LEVEL_BYTE__NO_PRE__SHIFT 0x5u
|
||||
#define PRESET_LEVEL_BYTE__NO_PRE__MASK 0x20u
|
||||
// Enable no demphasis bit[6]
|
||||
#define PRESET_LEVEL_BYTE__NO_DEMPH__SHIFT 0x6u
|
||||
#define PRESET_LEVEL_BYTE__NO_DEMPH__MASK 0x40u
|
||||
// Enable method 2 bit[7]
|
||||
#define PRESET_LEVEL_BYTE__METHOD_2__SHIFT 0x7u
|
||||
#define PRESET_LEVEL_BYTE__METHOD_2__MASK 0x80u
|
||||
|
||||
void enc60_hw_init(struct link_encoder *enc)
|
||||
{
|
||||
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
|
||||
|
||||
switch (enc10->base.connector.id) {
|
||||
case CONNECTOR_ID_DISPLAY_PORT:
|
||||
case CONNECTOR_ID_EDP:
|
||||
AUX_REG_WRITE(AUX_DPHY_RX_CONTROL0, 0x103d1110);
|
||||
AUX_REG_WRITE(AUX_DPHY_TX_CONTROL, 0x21c7a);
|
||||
dcn10_aux_initialize(enc10);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
REG_UPDATE(TMDS_CTL_BITS, TMDS_CTL0, 1);
|
||||
|
||||
// Polarity update is handled by DMU init.
|
||||
// AUX_PAD_MODE update done by DMU init
|
||||
}
|
||||
|
||||
static enum bp_result link_transmitter_control(
|
||||
struct dcn10_link_encoder *enc10,
|
||||
struct bp_transmitter_control *cntl)
|
||||
{
|
||||
enum bp_result result;
|
||||
struct dc_bios *bp = enc10->base.ctx->dc_bios;
|
||||
|
||||
result = bp->funcs->transmitter_control(bp, cntl);
|
||||
|
||||
return result;
|
||||
}
|
||||
//---------------------------------------------------
|
||||
// Task: Program EQ setting
|
||||
// Note:
|
||||
// EQ setting can be dont during P2 state or P0 state
|
||||
// If set in P0 state, The values are latched in a single
|
||||
// cycle of txX_clk but will take maximum of 40 txX_clk symbols
|
||||
// to be reflected on the output. During this period the
|
||||
// analog serial lines might have a transitional behavior.
|
||||
//---------------------------------------------------
|
||||
|
||||
void dpcs60_program_eq_setting(
|
||||
struct link_encoder *enc,
|
||||
uint8_t FFE_Level,
|
||||
bool de_emphasis_only,
|
||||
bool pre_shoot_only,
|
||||
bool no_ffe,
|
||||
const struct dc_hdmi_frl_link_settings *link_settings)
|
||||
{
|
||||
const uint8_t max_ffe_level =
|
||||
(link_settings->frl_link_rate > HDMI_FRL_LINK_RATE_12GBPS) ? 0x7 : 0x3;
|
||||
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
|
||||
struct bp_transmitter_control cntl = { 0 };
|
||||
|
||||
if (enc10->base.ctx->dc->debug.ignore_ffe)
|
||||
return;
|
||||
|
||||
if (FFE_Level <= max_ffe_level)
|
||||
enc10->base.txffe_state = FFE_Level;
|
||||
|
||||
if (enc10->base.ctx->dc->debug.select_ffe)
|
||||
enc10->base.txffe_state =
|
||||
(uint8_t)enc10->base.ctx->dc->debug.select_ffe;
|
||||
|
||||
if (FFE_Level == 0xEE) {
|
||||
enc10->base.txffe_state++;
|
||||
if (enc10->base.txffe_state > max_ffe_level)
|
||||
enc10->base.txffe_state = 0;
|
||||
}
|
||||
|
||||
if (no_ffe) {
|
||||
de_emphasis_only = true;
|
||||
pre_shoot_only = true;
|
||||
}
|
||||
/* Pass on the input params to DMCUB for proper calc of eq settings */
|
||||
cntl.lane_settings = ((de_emphasis_only ? 1u : 0u) << PRESET_LEVEL_BYTE__NO_PRE__SHIFT) |
|
||||
((pre_shoot_only ? 1u : 0u) << PRESET_LEVEL_BYTE__NO_DEMPH__SHIFT) |
|
||||
((enc10->base.txffe_state & PRESET_LEVEL_BYTE__LEVEL__MASK)
|
||||
<< PRESET_LEVEL_BYTE__LEVEL__SHIFT);
|
||||
cntl.lane_select = 0;
|
||||
cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
|
||||
cntl.transmitter = enc10->base.transmitter;
|
||||
cntl.connector_obj_id = enc10->base.connector;
|
||||
cntl.lanes_number = link_settings->frl_num_lanes;
|
||||
cntl.hpd_sel = enc10->base.hpd_source;
|
||||
/* Use below or dc_link_frl_bandwidth_kbps()? */
|
||||
switch (link_settings->frl_link_rate) {
|
||||
case HDMI_FRL_LINK_RATE_3GBPS:
|
||||
cntl.pixel_clock = 166667 / 10;
|
||||
break;
|
||||
case HDMI_FRL_LINK_RATE_6GBPS:
|
||||
case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
|
||||
cntl.pixel_clock = 333333 / 10;
|
||||
break;
|
||||
case HDMI_FRL_LINK_RATE_8GBPS:
|
||||
cntl.pixel_clock = 444444 / 10;
|
||||
break;
|
||||
case HDMI_FRL_LINK_RATE_10GBPS:
|
||||
cntl.pixel_clock = 555555 / 10;
|
||||
break;
|
||||
case HDMI_FRL_LINK_RATE_12GBPS:
|
||||
cntl.pixel_clock = 666667 / 10;
|
||||
break;
|
||||
case HDMI_FRL_LINK_RATE_16GBPS:
|
||||
cntl.pixel_clock = 888889 / 10;
|
||||
break;
|
||||
case HDMI_FRL_LINK_RATE_20GBPS:
|
||||
default:
|
||||
cntl.pixel_clock = 1111111 / 10;
|
||||
break;
|
||||
}
|
||||
/* call VBIOS table to set eq settings - voltage swing and pre-emphasis */
|
||||
link_transmitter_control(enc10, &cntl);
|
||||
}
|
||||
|
||||
static const struct link_encoder_funcs dcn60_link_enc_funcs = {
|
||||
.read_state = link_enc2_read_state,
|
||||
.validate_output_with_stream =
|
||||
dcn30_link_encoder_validate_output_with_stream,
|
||||
.hw_init = enc60_hw_init,
|
||||
.setup = dcn401_link_encoder_setup,
|
||||
.enable_tmds_output = dcn10_link_encoder_enable_tmds_output,
|
||||
.enable_dp_output = dcn401_link_encoder_enable_dp_output,
|
||||
.enable_dp_mst_output = dcn10_link_encoder_enable_dp_mst_output,
|
||||
.disable_output = dcn10_link_encoder_disable_output,
|
||||
.dp_set_lane_settings = dcn10_link_encoder_dp_set_lane_settings,
|
||||
.dp_set_phy_pattern = dcn10_link_encoder_dp_set_phy_pattern,
|
||||
.update_mst_stream_allocation_table =
|
||||
dcn10_link_encoder_update_mst_stream_allocation_table,
|
||||
.psr_program_dp_dphy_fast_training =
|
||||
dcn10_psr_program_dp_dphy_fast_training,
|
||||
.psr_program_secondary_packet = dcn10_psr_program_secondary_packet,
|
||||
.connect_dig_be_to_fe = dcn10_link_encoder_connect_dig_be_to_fe,
|
||||
.enable_hpd = dcn10_link_encoder_enable_hpd,
|
||||
.disable_hpd = dcn10_link_encoder_disable_hpd,
|
||||
.is_dig_enabled = dcn401_is_dig_enabled,
|
||||
.destroy = dcn10_link_encoder_destroy,
|
||||
.fec_set_enable = enc2_fec_set_enable,
|
||||
.fec_set_ready = enc2_fec_set_ready,
|
||||
.fec_is_active = enc2_fec_is_active,
|
||||
.get_dig_frontend = dcn10_get_dig_frontend,
|
||||
.get_dig_mode = dcn401_get_dig_mode,
|
||||
.is_in_alt_mode = dcn32_link_encoder_is_in_alt_mode,
|
||||
.get_max_link_cap = dcn32_link_encoder_get_max_link_cap,
|
||||
.dpcstx_set_order_invert_18_bit = NULL,
|
||||
.set_phy_source = NULL,
|
||||
.dpcs_initialize_phy = NULL,
|
||||
.dpcs_configure_phypll = NULL,
|
||||
.dpcs_configure_dpcs = NULL,
|
||||
.dpcs_enable_dpcs = NULL,
|
||||
.prog_eq_setting = dpcs60_program_eq_setting,
|
||||
.get_txffe = dpcs401_get_txffe,
|
||||
.set_txffe = dpcs401_set_txffe,
|
||||
.set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
|
||||
.setup_ri_pj_check_in_sw_or_hw_mode = dcn401_setup_ri_pj_check_in_sw_or_hw_mode,
|
||||
.get_hpd_state = dcn42_get_hpd_state,
|
||||
.program_hpd_filter = dcn42_program_hpd_filter,
|
||||
};
|
||||
|
||||
void dcn60_link_encoder_construct(
|
||||
struct dcn20_link_encoder *enc20,
|
||||
const struct encoder_init_data *init_data,
|
||||
const struct encoder_feature_support *enc_features,
|
||||
const struct dcn10_link_enc_registers *link_regs,
|
||||
const struct dcn10_link_enc_aux_registers *aux_regs,
|
||||
const struct dcn10_link_enc_hpd_registers *hpd_regs,
|
||||
const struct dcn10_link_enc_shift *link_shift,
|
||||
const struct dcn10_link_enc_mask *link_mask)
|
||||
{
|
||||
struct bp_connector_speed_cap_info bp_cap_info = {0};
|
||||
const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs;
|
||||
enum bp_result result = BP_RESULT_OK;
|
||||
struct dcn10_link_encoder *enc10 = &enc20->enc10;
|
||||
|
||||
enc10->base.funcs = &dcn60_link_enc_funcs;
|
||||
enc10->base.ctx = init_data->ctx;
|
||||
enc10->base.id = init_data->encoder;
|
||||
|
||||
enc10->base.hpd_source = init_data->hpd_source;
|
||||
enc10->base.hpd_active_high = init_data->hpd_active_high;
|
||||
enc10->base.connector = init_data->connector;
|
||||
|
||||
enc10->base.preferred_engine = ENGINE_ID_UNKNOWN;
|
||||
|
||||
enc10->base.features = *enc_features;
|
||||
if (enc10->base.connector.id == CONNECTOR_ID_USBC)
|
||||
enc10->base.features.flags.bits.DP_IS_USB_C = 1;
|
||||
|
||||
enc10->base.transmitter = init_data->transmitter;
|
||||
|
||||
/* set the flag to indicate whether driver poll the I2C data pin
|
||||
* while doing the DP sink detect
|
||||
*/
|
||||
|
||||
/* if (dal_adapter_service_is_feature_supported(as,
|
||||
FEATURE_DP_SINK_DETECT_POLL_DATA_PIN))
|
||||
enc10->base.features.flags.bits.
|
||||
DP_SINK_DETECT_POLL_DATA_PIN = true;*/
|
||||
|
||||
enc10->base.output_signals =
|
||||
SIGNAL_TYPE_DVI_SINGLE_LINK |
|
||||
SIGNAL_TYPE_DVI_DUAL_LINK |
|
||||
SIGNAL_TYPE_LVDS |
|
||||
SIGNAL_TYPE_DISPLAY_PORT |
|
||||
SIGNAL_TYPE_DISPLAY_PORT_MST |
|
||||
SIGNAL_TYPE_EDP |
|
||||
SIGNAL_TYPE_HDMI_TYPE_A;
|
||||
|
||||
enc10->link_regs = link_regs;
|
||||
enc10->aux_regs = aux_regs;
|
||||
enc10->hpd_regs = hpd_regs;
|
||||
enc10->link_shift = link_shift;
|
||||
enc10->link_mask = link_mask;
|
||||
|
||||
switch (enc10->base.transmitter) {
|
||||
case TRANSMITTER_UNIPHY_A:
|
||||
enc10->base.preferred_engine = ENGINE_ID_DIGA;
|
||||
break;
|
||||
case TRANSMITTER_UNIPHY_B:
|
||||
enc10->base.preferred_engine = ENGINE_ID_DIGB;
|
||||
break;
|
||||
case TRANSMITTER_UNIPHY_C:
|
||||
enc10->base.preferred_engine = ENGINE_ID_DIGC;
|
||||
break;
|
||||
case TRANSMITTER_UNIPHY_D:
|
||||
enc10->base.preferred_engine = ENGINE_ID_DIGD;
|
||||
break;
|
||||
case TRANSMITTER_UNIPHY_E:
|
||||
enc10->base.preferred_engine = ENGINE_ID_DIGE;
|
||||
break;
|
||||
default:
|
||||
ASSERT_CRITICAL(false);
|
||||
enc10->base.preferred_engine = ENGINE_ID_UNKNOWN;
|
||||
}
|
||||
|
||||
/* default to one to mirror Windows behavior */
|
||||
enc10->base.features.flags.bits.HDMI_6GB_EN = 1;
|
||||
|
||||
if (bp_funcs->get_connector_speed_cap_info)
|
||||
result = bp_funcs->get_connector_speed_cap_info(enc10->base.ctx->dc_bios,
|
||||
enc10->base.connector, &bp_cap_info);
|
||||
|
||||
/* Override features with DCE-specific values */
|
||||
if (result == BP_RESULT_OK) {
|
||||
enc10->base.features.flags.bits.IS_HBR2_CAPABLE =
|
||||
bp_cap_info.DP_HBR2_EN;
|
||||
enc10->base.features.flags.bits.IS_HBR3_CAPABLE =
|
||||
bp_cap_info.DP_HBR3_EN;
|
||||
enc10->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN;
|
||||
enc10->base.features.flags.bits.IS_DP2_CAPABLE = 1;
|
||||
enc10->base.features.flags.bits.IS_UHBR10_CAPABLE = bp_cap_info.DP_UHBR10_EN;
|
||||
enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
|
||||
enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
|
||||
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE =
|
||||
bp_cap_info.FRL_8G_EN || bp_cap_info.FRL_10G_EN || bp_cap_info.FRL_12G_EN ||
|
||||
bp_cap_info.FRL_16G_EN || bp_cap_info.FRL_20G_EN || bp_cap_info.FRL_24G_EN;
|
||||
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
|
||||
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
|
||||
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
|
||||
enc10->base.features.flags.bits.IS_FRL_16G_CAPABLE = bp_cap_info.FRL_16G_EN;
|
||||
enc10->base.features.flags.bits.IS_FRL_20G_CAPABLE = bp_cap_info.FRL_20G_EN;
|
||||
enc10->base.features.flags.bits.IS_FRL_24G_CAPABLE = bp_cap_info.FRL_24G_EN;
|
||||
enc10->base.txffe_state = 0;
|
||||
} else {
|
||||
DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
|
||||
__func__,
|
||||
result);
|
||||
}
|
||||
if (enc10->base.ctx->dc->debug.hdmi20_disable) {
|
||||
enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
|
||||
}
|
||||
if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
|
||||
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
|
||||
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
|
||||
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
|
||||
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
|
||||
enc10->base.features.flags.bits.IS_FRL_16G_CAPABLE = 1;
|
||||
enc10->base.features.flags.bits.IS_FRL_20G_CAPABLE = 1;
|
||||
enc10->base.features.flags.bits.IS_FRL_24G_CAPABLE = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright 2025 Advanced Micro Devices, Inc.
|
||||
|
||||
#ifndef __DC_LINK_ENCODER__DCN60_H__
|
||||
#define __DC_LINK_ENCODER__DCN60_H__
|
||||
|
||||
#include "dcn30/dcn30_dio_link_encoder.h"
|
||||
|
||||
#define LINK_ENCODER_MASK_SH_LIST_DCN60(mask_sh) \
|
||||
LE_SF(DIG0_HDCP_I2C_CONTROL_0, HDCP_I2C_DISABLE, mask_sh),\
|
||||
LE_SF(DIG0_HDCP_I2C_CONTROL_0, HDCP_I2C_DDC_SELECT, mask_sh),\
|
||||
LE_SF(DIG0_HDCP_INT_CONTROL, HDCP_I2C_XFER_REQ_MASK, mask_sh),\
|
||||
LE_SF(HPD0_DC_HPD_INT_STATUS, DC_HPD_SENSE, mask_sh),\
|
||||
LE_SF(HPD0_DC_HPD_TOGGLE_FILT_CNTL, DC_HPD_CONNECT_INT_DELAY, mask_sh),\
|
||||
LE_SF(HPD0_DC_HPD_TOGGLE_FILT_CNTL, DC_HPD_DISCONNECT_INT_DELAY, mask_sh),\
|
||||
LE_SF(DC_GPIO_DDC1_MASK, AUX_PAD1_MODE, mask_sh),\
|
||||
SF(HPD_CTRL, HPD1_Y_POL_INVERT, mask_sh),\
|
||||
SF(HPD_CTRL, HPD2_Y_POL_INVERT, mask_sh),\
|
||||
SF(HPD_CTRL, HPD3_Y_POL_INVERT, mask_sh),\
|
||||
SF(HPD_CTRL, HPD4_Y_POL_INVERT, mask_sh)
|
||||
|
||||
void dcn60_link_encoder_construct(
|
||||
struct dcn20_link_encoder *enc20,
|
||||
const struct encoder_init_data *init_data,
|
||||
const struct encoder_feature_support *enc_features,
|
||||
const struct dcn10_link_enc_registers *link_regs,
|
||||
const struct dcn10_link_enc_aux_registers *aux_regs,
|
||||
const struct dcn10_link_enc_hpd_registers *hpd_regs,
|
||||
const struct dcn10_link_enc_shift *link_shift,
|
||||
const struct dcn10_link_enc_mask *link_mask);
|
||||
|
||||
void dpcs60_program_eq_setting(
|
||||
struct link_encoder *enc,
|
||||
uint8_t FFE_Level,
|
||||
bool de_emphasis_only,
|
||||
bool pre_shoot_only,
|
||||
bool no_ffe,
|
||||
const struct dc_hdmi_frl_link_settings *link_settings);
|
||||
|
||||
void enc60_hw_init(struct link_encoder *enc);
|
||||
|
||||
#endif /* __DC_LINK_ENCODER__DCN60_H__ */
|
||||
@@ -0,0 +1,538 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright 2025 Advanced Micro Devices, Inc.
|
||||
|
||||
#include "dc_bios_types.h"
|
||||
#include "dcn30/dcn30_dio_stream_encoder.h"
|
||||
#include "dcn32/dcn32_dio_stream_encoder.h"
|
||||
#include "dcn35/dcn35_dio_stream_encoder.h"
|
||||
#include "dcn401/dcn401_dio_stream_encoder.h"
|
||||
|
||||
#include "dcn60_dio_stream_encoder.h"
|
||||
#include "reg_helper.h"
|
||||
#include "hw_shared.h"
|
||||
#include "link_service.h"
|
||||
#include "dpcd_defs.h"
|
||||
|
||||
#define DC_LOGGER \
|
||||
enc1->base.ctx->logger
|
||||
|
||||
#define REG(reg)\
|
||||
(enc1->regs->reg)
|
||||
|
||||
#undef FN
|
||||
#define FN(reg_name, field_name) \
|
||||
(uint8_t)enc1->se_shift->field_name, enc1->se_mask->field_name
|
||||
|
||||
#define VBI_LINE_0 0
|
||||
#define HDMI_CLOCK_CHANNEL_RATE_MORE_340M 340000
|
||||
|
||||
#define CTX \
|
||||
enc1->base.ctx
|
||||
|
||||
static void enc60_dp_set_odm_combine(
|
||||
struct stream_encoder *enc,
|
||||
bool odm_combine)
|
||||
{
|
||||
(void)enc;
|
||||
(void)odm_combine;
|
||||
}
|
||||
|
||||
/* setup stream encoder in hdmi mode */
|
||||
static void enc60_stream_encoder_hdmi_set_stream_attribute(
|
||||
struct stream_encoder *enc,
|
||||
struct dc_crtc_timing *crtc_timing,
|
||||
int actual_pix_clk_khz,
|
||||
bool enable_audio)
|
||||
{
|
||||
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
|
||||
|
||||
if (!enc->ctx->dc->debug.avoid_vbios_exec_table) {
|
||||
struct bp_encoder_control cntl = {0};
|
||||
|
||||
cntl.action = ENCODER_CONTROL_SETUP;
|
||||
cntl.engine_id = enc1->base.id;
|
||||
cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A;
|
||||
cntl.enable_dp_audio = enable_audio;
|
||||
cntl.pixel_clock = actual_pix_clk_khz;
|
||||
cntl.lanes_number = LANE_COUNT_FOUR;
|
||||
|
||||
if (enc1->base.bp->funcs->encoder_control(
|
||||
enc1->base.bp, &cntl) != BP_RESULT_OK)
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
||||
//Set pattern for clock channel, default vlue 0x63 does not work
|
||||
REG_UPDATE(DIG_CLOCK_PATTERN, DIG_CLOCK_PATTERN, 0x1F);
|
||||
|
||||
//DIG_BE_TMDS_HDMI_MODE : TMDS-HDMI mode is already set in link_encoder_setup
|
||||
|
||||
//DIG_SOURCE_SELECT is already set in dig_connect_to_otg
|
||||
|
||||
/* DIG_START is removed from the register spec */
|
||||
}
|
||||
|
||||
/* Configure pixel encoding */
|
||||
enc401_stream_encoder_set_stream_attribute_helper(enc1, crtc_timing);
|
||||
|
||||
/* setup HDMI engine */
|
||||
REG_UPDATE_4(HDMI_CONTROL,
|
||||
HDMI_DEEP_COLOR_ENABLE, 0,
|
||||
HDMI_DATA_SCRAMBLE_EN, 0,
|
||||
HDMI_NO_EXTRA_NULL_PACKET_FILLED, 1,
|
||||
HDMI_CLOCK_CHANNEL_RATE, 0);
|
||||
|
||||
/* Configure color depth */
|
||||
switch (crtc_timing->display_color_depth) {
|
||||
case COLOR_DEPTH_888:
|
||||
REG_UPDATE(HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 0);
|
||||
break;
|
||||
case COLOR_DEPTH_101010:
|
||||
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
|
||||
REG_UPDATE_2(HDMI_CONTROL,
|
||||
HDMI_DEEP_COLOR_DEPTH, 1,
|
||||
HDMI_DEEP_COLOR_ENABLE, 0);
|
||||
} else {
|
||||
REG_UPDATE_2(HDMI_CONTROL,
|
||||
HDMI_DEEP_COLOR_DEPTH, 1,
|
||||
HDMI_DEEP_COLOR_ENABLE, 1);
|
||||
}
|
||||
break;
|
||||
case COLOR_DEPTH_121212:
|
||||
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
|
||||
REG_UPDATE_2(HDMI_CONTROL,
|
||||
HDMI_DEEP_COLOR_DEPTH, 2,
|
||||
HDMI_DEEP_COLOR_ENABLE, 0);
|
||||
} else {
|
||||
REG_UPDATE_2(HDMI_CONTROL,
|
||||
HDMI_DEEP_COLOR_DEPTH, 2,
|
||||
HDMI_DEEP_COLOR_ENABLE, 1);
|
||||
}
|
||||
break;
|
||||
case COLOR_DEPTH_161616:
|
||||
REG_UPDATE_2(HDMI_CONTROL,
|
||||
HDMI_DEEP_COLOR_DEPTH, 3,
|
||||
HDMI_DEEP_COLOR_ENABLE, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (actual_pix_clk_khz >= HDMI_CLOCK_CHANNEL_RATE_MORE_340M) {
|
||||
/* enable HDMI data scrambler
|
||||
* HDMI_CLOCK_CHANNEL_RATE_MORE_340M
|
||||
* Clock channel frequency is 1/4 of character rate.
|
||||
*/
|
||||
REG_UPDATE_2(HDMI_CONTROL,
|
||||
HDMI_DATA_SCRAMBLE_EN, 1,
|
||||
HDMI_CLOCK_CHANNEL_RATE, 1);
|
||||
} else if (crtc_timing->flags.LTE_340MCSC_SCRAMBLE) {
|
||||
|
||||
/* TODO: New feature for DCE11, still need to implement */
|
||||
|
||||
/* enable HDMI data scrambler
|
||||
* HDMI_CLOCK_CHANNEL_FREQ_EQUAL_TO_CHAR_RATE
|
||||
* Clock channel frequency is the same
|
||||
* as character rate
|
||||
*/
|
||||
REG_UPDATE_2(HDMI_CONTROL,
|
||||
HDMI_DATA_SCRAMBLE_EN, 1,
|
||||
HDMI_CLOCK_CHANNEL_RATE, 0);
|
||||
}
|
||||
|
||||
/* Enable transmission of General Control packet on every frame */
|
||||
REG_UPDATE_3(HDMI_VBI_PACKET_CONTROL,
|
||||
HDMI_GC_CONT, 1,
|
||||
HDMI_GC_SEND, 1,
|
||||
HDMI_NULL_SEND, 1);
|
||||
|
||||
/* Disable Audio Content Protection packet transmission */
|
||||
REG_UPDATE(HDMI_VBI_PACKET_CONTROL, HDMI_ACP_SEND, 0);
|
||||
/* following belongs to audio */
|
||||
/* Enable Audio InfoFrame packet transmission. */
|
||||
REG_UPDATE(HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_SEND, 1);
|
||||
|
||||
/* update double-buffered AUDIO_INFO registers immediately */
|
||||
// ASSERT(enc->afmt);
|
||||
// enc->afmt->funcs->audio_info_immediate_update(enc->afmt);
|
||||
|
||||
/* Select line number on which to send Audio InfoFrame packets */
|
||||
REG_UPDATE(HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_LINE,
|
||||
VBI_LINE_0 + 2);
|
||||
|
||||
/* set HDMI GC AVMUTE */
|
||||
REG_UPDATE(HDMI_GC, HDMI_GC_AVMUTE, 0);
|
||||
}
|
||||
|
||||
static void enc60_stream_encoder_update_hdmi_info_packets(
|
||||
struct stream_encoder *enc,
|
||||
const struct encoder_info_frame *info_frame)
|
||||
{
|
||||
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
|
||||
|
||||
/* for bring up, disable dp double TODO */
|
||||
REG_UPDATE(HDMI_DB_CONTROL, HDMI_DB_DISABLE, 1);
|
||||
REG_UPDATE(DIG_FE_AUDIO_CNTL, APG_CLOCK_ENABLE, 1);
|
||||
|
||||
/*Always add mandatory packets first followed by optional ones*/
|
||||
enc3_update_hdmi_info_packet(enc1, 0, &info_frame->avi);
|
||||
enc3_update_hdmi_info_packet(enc1, 5, &info_frame->hfvsif);
|
||||
enc3_update_hdmi_info_packet(enc1, 2, &info_frame->gamut);
|
||||
enc3_update_hdmi_info_packet(enc1, 1, &info_frame->vendor);
|
||||
enc3_update_hdmi_info_packet(enc1, 3, &info_frame->spd);
|
||||
enc3_update_hdmi_info_packet(enc1, 4, &info_frame->hdrsmd);
|
||||
enc3_update_hdmi_info_packet(enc1, 6, &info_frame->vtem);
|
||||
}
|
||||
|
||||
static void enc60_se_enable_audio_clock(
|
||||
struct stream_encoder *enc,
|
||||
bool enable)
|
||||
{
|
||||
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
|
||||
|
||||
REG_UPDATE(DIG_FE_AUDIO_CNTL, APG_CLOCK_ENABLE, enable);
|
||||
}
|
||||
|
||||
static void enc60_se_setup_hdmi_audio(
|
||||
struct stream_encoder *enc,
|
||||
const struct audio_crtc_info *crtc_info)
|
||||
{
|
||||
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
|
||||
|
||||
struct audio_clock_info audio_clock_info = {0};
|
||||
|
||||
/* HDMI_AUDIO_PACKET_CONTROL */
|
||||
REG_UPDATE(HDMI_AUDIO_PACKET_CONTROL,
|
||||
HDMI_AUDIO_DELAY_EN, 1);
|
||||
|
||||
/* HDMI_ACR_PACKET_CONTROL */
|
||||
REG_UPDATE_2(HDMI_ACR_PACKET_CONTROL,
|
||||
HDMI_ACR_AUTO_SEND, 1,
|
||||
HDMI_ACR_SOURCE, 0);
|
||||
|
||||
/* Program audio clock sample/regeneration parameters */
|
||||
get_audio_clock_info(crtc_info->color_depth,
|
||||
crtc_info->requested_pixel_clock_100Hz,
|
||||
crtc_info->calculated_pixel_clock_100Hz,
|
||||
&audio_clock_info);
|
||||
DC_LOG_HW_AUDIO(
|
||||
"\n%s:Input::requested_pixel_clock_100Hz = %d" \
|
||||
"calculated_pixel_clock_100Hz = %d \n", __func__, \
|
||||
crtc_info->requested_pixel_clock_100Hz, \
|
||||
crtc_info->calculated_pixel_clock_100Hz);
|
||||
|
||||
/* HDMI_ACR_32_0__HDMI_ACR_CTS_32_MASK */
|
||||
REG_UPDATE(HDMI_ACR_32_0, HDMI_ACR_CTS_32, audio_clock_info.cts_32khz);
|
||||
|
||||
/* HDMI_ACR_32_1__HDMI_ACR_N_32_MASK */
|
||||
REG_UPDATE(HDMI_ACR_32_1, HDMI_ACR_N_32, audio_clock_info.n_32khz);
|
||||
|
||||
/* HDMI_ACR_44_0__HDMI_ACR_CTS_44_MASK */
|
||||
REG_UPDATE(HDMI_ACR_44_0, HDMI_ACR_CTS_44, audio_clock_info.cts_44khz);
|
||||
|
||||
/* HDMI_ACR_44_1__HDMI_ACR_N_44_MASK */
|
||||
REG_UPDATE(HDMI_ACR_44_1, HDMI_ACR_N_44, audio_clock_info.n_44khz);
|
||||
|
||||
/* HDMI_ACR_48_0__HDMI_ACR_CTS_48_MASK */
|
||||
REG_UPDATE(HDMI_ACR_48_0, HDMI_ACR_CTS_48, audio_clock_info.cts_48khz);
|
||||
|
||||
/* HDMI_ACR_48_1__HDMI_ACR_N_48_MASK */
|
||||
REG_UPDATE(HDMI_ACR_48_1, HDMI_ACR_N_48, audio_clock_info.n_48khz);
|
||||
|
||||
/* Video driver cannot know in advance which sample rate will
|
||||
* be used by HD Audio driver
|
||||
* HDMI_ACR_PACKET_CONTROL__HDMI_ACR_N_MULTIPLE field is
|
||||
* programmed below in interruppt callback
|
||||
*/
|
||||
}
|
||||
|
||||
static void enc60_se_hdmi_audio_setup(
|
||||
struct stream_encoder *enc,
|
||||
unsigned int az_inst,
|
||||
struct audio_info *info,
|
||||
struct audio_crtc_info *audio_crtc_info)
|
||||
{
|
||||
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
|
||||
|
||||
enc60_se_enable_audio_clock(enc, true);
|
||||
enc60_se_setup_hdmi_audio(enc, audio_crtc_info);
|
||||
|
||||
REG_UPDATE(DIG_FE_AUDIO_CNTL,
|
||||
DIG_FE_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, az_inst);
|
||||
ASSERT (enc->apg);
|
||||
enc->apg->funcs->se_audio_setup(enc->apg, az_inst, info);
|
||||
}
|
||||
|
||||
static void enc60_se_hdmi_audio_disable(
|
||||
struct stream_encoder *enc)
|
||||
{
|
||||
ASSERT (enc->apg);
|
||||
if (enc->apg && enc->apg->funcs->disable_apg)
|
||||
enc->apg->funcs->disable_apg(enc->apg);
|
||||
|
||||
enc60_se_enable_audio_clock(enc, false);
|
||||
}
|
||||
|
||||
static void enc60_stream_encoder_stop_dp_info_packets(
|
||||
struct stream_encoder *enc)
|
||||
{
|
||||
/* stop generic packets on DP */
|
||||
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
|
||||
uint32_t value = 0;
|
||||
|
||||
REG_SET_9(DP_SEC_CNTL, 0,
|
||||
DP_SEC_GSP0_ENABLE, 0,
|
||||
DP_SEC_GSP1_ENABLE, 0,
|
||||
DP_SEC_GSP2_ENABLE, 0,
|
||||
DP_SEC_GSP3_ENABLE, 0,
|
||||
DP_SEC_GSP4_ENABLE, 0,
|
||||
DP_SEC_GSP5_ENABLE, 0,
|
||||
DP_SEC_GSP6_ENABLE, 0,
|
||||
DP_SEC_GSP7_ENABLE, 0,
|
||||
DP_SEC_STREAM_ENABLE, 0);
|
||||
|
||||
/* this register shared with audio info frame.
|
||||
* therefore we need to keep master enabled
|
||||
* if at least one of the fields is not 0 */
|
||||
value = REG_READ(DP_SEC_CNTL);
|
||||
if (value)
|
||||
REG_UPDATE(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1);
|
||||
|
||||
}
|
||||
|
||||
#define DP_SEC_AUD_N__DP_SEC_AUD_N__DEFAULT 0x8000
|
||||
#define DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUTO_CALC 1
|
||||
|
||||
static void enc60_se_setup_dp_audio(
|
||||
struct stream_encoder *enc)
|
||||
{
|
||||
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
|
||||
|
||||
/* --- DP Audio packet configurations --- */
|
||||
|
||||
/* ATP Configuration */
|
||||
REG_SET(DP_SEC_AUD_N, 0,
|
||||
DP_SEC_AUD_N, DP_SEC_AUD_N__DP_SEC_AUD_N__DEFAULT);
|
||||
|
||||
/* Async/auto-calc timestamp mode */
|
||||
REG_SET(DP_SEC_TIMESTAMP, 0, DP_SEC_TIMESTAMP_MODE,
|
||||
DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUTO_CALC);
|
||||
}
|
||||
|
||||
static void enc60_se_dp_audio_enable(
|
||||
struct stream_encoder *enc)
|
||||
{
|
||||
enc60_se_enable_audio_clock(enc, true);
|
||||
enc60_se_setup_dp_audio(enc);
|
||||
enc1_se_enable_dp_audio(enc);
|
||||
|
||||
/* Enable APG block */
|
||||
enc->apg->funcs->enable_apg(enc->apg);
|
||||
}
|
||||
|
||||
static void enc60_se_disable_dp_audio(
|
||||
struct stream_encoder *enc)
|
||||
{
|
||||
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
|
||||
uint32_t value = 0;
|
||||
|
||||
/* Disable Audio packets */
|
||||
REG_UPDATE_5(DP_SEC_CNTL,
|
||||
DP_SEC_ASP_ENABLE, 0,
|
||||
DP_SEC_ATP_ENABLE, 0,
|
||||
DP_SEC_AIP_ENABLE, 0,
|
||||
DP_SEC_ACM_ENABLE, 0,
|
||||
DP_SEC_STREAM_ENABLE, 0);
|
||||
|
||||
/* This register shared with encoder info frame. Therefore we need to
|
||||
* keep master enabled if at least on of the fields is not 0
|
||||
*/
|
||||
value = REG_READ(DP_SEC_CNTL);
|
||||
if (value != 0)
|
||||
REG_UPDATE(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1);
|
||||
}
|
||||
|
||||
static void enc60_se_dp_audio_disable(
|
||||
struct stream_encoder *enc)
|
||||
{
|
||||
enc60_se_disable_dp_audio(enc);
|
||||
|
||||
/* Disable APG block */
|
||||
enc->apg->funcs->disable_apg(enc->apg);
|
||||
|
||||
enc60_se_enable_audio_clock(enc, false);
|
||||
}
|
||||
|
||||
static void enc60_audio_mute_control(
|
||||
struct stream_encoder *enc,
|
||||
bool mute)
|
||||
{
|
||||
ASSERT (enc->apg);
|
||||
if (mute)
|
||||
enc->apg->funcs->disable_apg(enc->apg);
|
||||
else
|
||||
enc->apg->funcs->enable_apg(enc->apg);
|
||||
|
||||
}
|
||||
|
||||
static void enc60_se_dp_audio_setup(
|
||||
struct stream_encoder *enc,
|
||||
unsigned int az_inst,
|
||||
struct audio_info *info)
|
||||
{
|
||||
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
|
||||
|
||||
enc60_se_enable_audio_clock(enc, true);
|
||||
|
||||
/*ACR setup*/
|
||||
REG_UPDATE(DIG_FE_AUDIO_CNTL,
|
||||
DIG_FE_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, az_inst);
|
||||
|
||||
ASSERT(enc->apg);
|
||||
enc->apg->funcs->se_audio_setup(enc->apg, az_inst, info);
|
||||
}
|
||||
|
||||
static void enc60_dp_set_dsc_pps_info_packet(struct stream_encoder *enc,
|
||||
bool enable,
|
||||
uint8_t *dsc_packed_pps,
|
||||
bool immediate_update)
|
||||
{
|
||||
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
|
||||
|
||||
if (enable) {
|
||||
struct dc_info_packet pps_sdp;
|
||||
int i;
|
||||
|
||||
/* Configure for PPS packet size (128 bytes) */
|
||||
REG_UPDATE(DP_SEC_CNTL2, DP_SEC_GSP11_PPS, 1);
|
||||
|
||||
/* Load PPS into infoframe (SDP) registers */
|
||||
pps_sdp.valid = true;
|
||||
pps_sdp.hb0 = 0;
|
||||
pps_sdp.hb1 = DC_DP_INFOFRAME_TYPE_PPS;
|
||||
pps_sdp.hb2 = 127;
|
||||
pps_sdp.hb3 = 0;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
memcpy(pps_sdp.sb, &dsc_packed_pps[i * 32], 32);
|
||||
enc1->base.vpg->funcs->update_generic_info_packet(
|
||||
enc1->base.vpg,
|
||||
11 + i,
|
||||
&pps_sdp,
|
||||
immediate_update);
|
||||
}
|
||||
|
||||
/* SW should make sure VBID[6] update line number is bigger
|
||||
* than PPS transmit line number
|
||||
*/
|
||||
REG_UPDATE(DP_GSP11_CNTL,
|
||||
DP_SEC_GSP11_LINE_NUM, 2);
|
||||
REG_UPDATE_2(DP_MSA_VBID_MISC,
|
||||
DP_VBID6_LINE_REFERENCE, 0,
|
||||
DP_VBID6_LINE_NUM, 3);
|
||||
|
||||
/* Send PPS data at the line number specified above.
|
||||
* DP spec requires PPS to be sent only when it changes, however since
|
||||
* decoder has to be able to handle its change on every frame, we're
|
||||
* sending it always (i.e. on every frame) to reduce the chance it'd be
|
||||
* missed by decoder. If it turns out required to send PPS only when it
|
||||
* changes, we can use DP_SEC_GSP11_SEND register.
|
||||
*/
|
||||
REG_UPDATE(DP_GSP11_CNTL,
|
||||
DP_SEC_GSP11_ENABLE, 1);
|
||||
REG_UPDATE(DP_SEC_CNTL,
|
||||
DP_SEC_STREAM_ENABLE, 1);
|
||||
} else {
|
||||
/* Disable Generic Stream Packet 11 (GSP) transmission */
|
||||
REG_UPDATE(DP_GSP11_CNTL, DP_SEC_GSP11_ENABLE, 0);
|
||||
REG_UPDATE(DP_SEC_CNTL2, DP_SEC_GSP11_PPS, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void enc60_reset_hdmi_stream_attribute(
|
||||
struct stream_encoder *enc)
|
||||
{
|
||||
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
|
||||
|
||||
REG_UPDATE_3(HDMI_CONTROL,
|
||||
HDMI_DEEP_COLOR_ENABLE, 0,
|
||||
HDMI_DATA_SCRAMBLE_EN, 0,
|
||||
HDMI_CLOCK_CHANNEL_RATE, 0);
|
||||
}
|
||||
|
||||
static const struct stream_encoder_funcs dcn60_str_enc_funcs = {
|
||||
.dp_set_odm_combine =
|
||||
enc60_dp_set_odm_combine,
|
||||
.dp_set_stream_attribute =
|
||||
enc401_stream_encoder_dp_set_stream_attribute,
|
||||
.hdmi_set_stream_attribute =
|
||||
enc60_stream_encoder_hdmi_set_stream_attribute,
|
||||
.dvi_set_stream_attribute =
|
||||
enc401_stream_encoder_dvi_set_stream_attribute,
|
||||
.set_throttled_vcp_size =
|
||||
enc1_stream_encoder_set_throttled_vcp_size,
|
||||
.update_hdmi_info_packets =
|
||||
enc60_stream_encoder_update_hdmi_info_packets,
|
||||
.stop_hdmi_info_packets =
|
||||
enc3_stream_encoder_stop_hdmi_info_packets,
|
||||
.update_dp_info_packets_sdp_line_num =
|
||||
enc3_stream_encoder_update_dp_info_packets_sdp_line_num,
|
||||
.update_dp_info_packets =
|
||||
enc3_stream_encoder_update_dp_info_packets,
|
||||
.stop_dp_info_packets =
|
||||
enc60_stream_encoder_stop_dp_info_packets,
|
||||
.dp_blank =
|
||||
enc1_stream_encoder_dp_blank,
|
||||
.dp_unblank =
|
||||
enc401_stream_encoder_dp_unblank,
|
||||
.audio_mute_control = enc60_audio_mute_control,
|
||||
|
||||
.dp_audio_setup = enc60_se_dp_audio_setup,
|
||||
.dp_audio_enable = enc60_se_dp_audio_enable,
|
||||
.dp_audio_disable = enc60_se_dp_audio_disable,
|
||||
|
||||
.hdmi_audio_setup = enc60_se_hdmi_audio_setup,
|
||||
.hdmi_audio_disable = enc60_se_hdmi_audio_disable,
|
||||
.setup_stereo_sync = enc1_setup_stereo_sync,
|
||||
.set_avmute = enc1_stream_encoder_set_avmute,
|
||||
.dig_connect_to_otg = enc1_dig_connect_to_otg,
|
||||
.dig_source_otg = enc1_dig_source_otg,
|
||||
|
||||
.dp_get_pixel_format = enc1_stream_encoder_dp_get_pixel_format,
|
||||
|
||||
.enc_read_state = enc401_read_state,
|
||||
.dp_set_dsc_config = NULL,
|
||||
.dp_set_dsc_pps_info_packet = enc60_dp_set_dsc_pps_info_packet,
|
||||
.set_dynamic_metadata = enc401_set_dynamic_metadata,
|
||||
.hdmi_reset_stream_attribute = enc60_reset_hdmi_stream_attribute,
|
||||
.enable_stream = enc401_stream_encoder_enable,
|
||||
|
||||
.set_input_mode = enc401_set_dig_input_mode,
|
||||
.enable_fifo = enc35_enable_fifo,
|
||||
.disable_fifo = enc35_disable_fifo,
|
||||
.map_stream_to_link = enc401_stream_encoder_map_to_link,
|
||||
};
|
||||
|
||||
void dcn60_dio_stream_encoder_construct(
|
||||
struct dcn10_stream_encoder *enc1,
|
||||
struct dc_context *ctx,
|
||||
struct dc_bios *bp,
|
||||
enum engine_id eng_id,
|
||||
struct vpg *vpg,
|
||||
struct apg *apg,
|
||||
const struct dcn10_stream_enc_registers *regs,
|
||||
const struct dcn10_stream_encoder_shift *se_shift,
|
||||
const struct dcn10_stream_encoder_mask *se_mask)
|
||||
{
|
||||
enc1->base.funcs = &dcn60_str_enc_funcs;
|
||||
enc1->base.ctx = ctx;
|
||||
enc1->base.id = eng_id;
|
||||
enc1->base.bp = bp;
|
||||
enc1->base.vpg = vpg;
|
||||
enc1->base.apg = apg;
|
||||
enc1->regs = regs;
|
||||
enc1->se_shift = se_shift;
|
||||
enc1->se_mask = se_mask;
|
||||
enc1->base.stream_enc_inst = vpg->inst;
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright 2025 Advanced Micro Devices, Inc.
|
||||
|
||||
#ifndef __DC_DIO_STREAM_ENCODER_DCN60_H__
|
||||
#define __DC_DIO_STREAM_ENCODER_DCN60_H__
|
||||
|
||||
#include "dcn30/dcn30_vpg.h"
|
||||
#include "dcn30/dcn30_afmt.h"
|
||||
#include "dcn31/dcn31_apg.h"
|
||||
#include "stream_encoder.h"
|
||||
#include "dcn20/dcn20_stream_encoder.h"
|
||||
|
||||
|
||||
#define SE_COMMON_MASK_SH_LIST_DCN60(mask_sh)\
|
||||
SE_SF(DP0_DP_PIXEL_FORMAT, PIXEL_ENCODING_TYPE, mask_sh),\
|
||||
SE_SF(DP0_DP_PIXEL_FORMAT, UNCOMPRESSED_PIXEL_FORMAT, mask_sh),\
|
||||
SE_SF(DP0_DP_PIXEL_FORMAT, UNCOMPRESSED_COMPONENT_DEPTH, mask_sh),\
|
||||
SE_SF(DP0_DP_PIXEL_FORMAT, COMPRESSED_PIXEL_FORMAT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_CONTROL, HDMI_DEEP_COLOR_ENABLE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_CONTROL, HDMI_DATA_SCRAMBLE_EN, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_CONTROL, HDMI_NO_EXTRA_NULL_PACKET_FILLED, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_VBI_PACKET_CONTROL, HDMI_GC_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_VBI_PACKET_CONTROL, HDMI_GC_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_VBI_PACKET_CONTROL, HDMI_NULL_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_VBI_PACKET_CONTROL, HDMI_ACP_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GC, HDMI_GC_AVMUTE, mask_sh),\
|
||||
SE_SF(DP0_DP_MSE_RATE_CNTL, DP_MSE_RATE_X, mask_sh),\
|
||||
SE_SF(DP0_DP_MSE_RATE_CNTL, DP_MSE_RATE_Y, mask_sh),\
|
||||
SE_SF(DP0_DP_MSE_RATE_UPDATE, DP_MSE_RATE_UPDATE_PENDING, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP0_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP1_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP2_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP3_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL1, DP_SEC_GSP5_LINE_REFERENCE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP4_SEND, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP4_SEND_PENDING, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL4, DP_SEC_GSP4_LINE_NUM, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL5, DP_SEC_GSP5_LINE_NUM, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP4_SEND_ANY_LINE, mask_sh),\
|
||||
SE_SF(DP0_DP_VID_STREAM_CNTL, DP_VID_STREAM_DIS_DEFER, mask_sh),\
|
||||
SE_SF(DP0_DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_VID_STREAM_CNTL, DP_VID_STREAM_STATUS, mask_sh),\
|
||||
SE_SF(DP0_DP_STEER_FIFO, DP_STEER_FIFO_RESET, mask_sh),\
|
||||
SE_SF(DP0_DP_STEER_FIFO, DP_STEER_FIFO_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_VID_TIMING, DP_VID_M_N_GEN_EN, mask_sh),\
|
||||
SE_SF(DP0_DP_VID_N, DP_VID_N, mask_sh),\
|
||||
SE_SF(DP0_DP_VID_M, DP_VID_M, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_AUDIO_PACKET_CONTROL, HDMI_AUDIO_DELAY_EN, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_ACR_PACKET_CONTROL, HDMI_ACR_AUTO_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_ACR_PACKET_CONTROL, HDMI_ACR_SOURCE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_ACR_32_0, HDMI_ACR_CTS_32, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_ACR_32_1, HDMI_ACR_N_32, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_ACR_44_0, HDMI_ACR_CTS_44, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_ACR_44_1, HDMI_ACR_N_44, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_ACR_48_0, HDMI_ACR_CTS_48, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_ACR_48_1, HDMI_ACR_N_48, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_AUD_N, DP_SEC_AUD_N, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_TIMESTAMP, DP_SEC_TIMESTAMP_MODE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_ASP_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_ATP_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_AIP_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_ACM_ENABLE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_CONTROL, HDMI_CLOCK_CHANNEL_RATE, mask_sh),\
|
||||
SE_SF(DIG1_HDMI_CONTROL, TMDS_PIXEL_ENCODING, mask_sh),\
|
||||
SE_SF(DIG1_HDMI_CONTROL, TMDS_COLOR_FORMAT, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_SELECT, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP4_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP5_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP6_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP7_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP7_SEND, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL6, DP_SEC_GSP7_LINE_NUM, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP11_PPS, mask_sh),\
|
||||
SE_SF(DP0_DP_GSP11_CNTL, DP_SEC_GSP11_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_GSP11_CNTL, DP_SEC_GSP11_LINE_NUM, mask_sh),\
|
||||
SE_SF(DP0_DP_DB_CNTL, DP_DB_DISABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_MSA_COLORIMETRY, DP_MSA_MISC0, mask_sh),\
|
||||
SE_SF(DP0_DP_MSA_TIMING_PARAM1, DP_MSA_HTOTAL, mask_sh),\
|
||||
SE_SF(DP0_DP_MSA_TIMING_PARAM1, DP_MSA_VTOTAL, mask_sh),\
|
||||
SE_SF(DP0_DP_MSA_TIMING_PARAM2, DP_MSA_HSTART, mask_sh),\
|
||||
SE_SF(DP0_DP_MSA_TIMING_PARAM2, DP_MSA_VSTART, mask_sh),\
|
||||
SE_SF(DP0_DP_MSA_TIMING_PARAM3, DP_MSA_HSYNCWIDTH, mask_sh),\
|
||||
SE_SF(DP0_DP_MSA_TIMING_PARAM3, DP_MSA_HSYNCPOLARITY, mask_sh),\
|
||||
SE_SF(DP0_DP_MSA_TIMING_PARAM3, DP_MSA_VSYNCWIDTH, mask_sh),\
|
||||
SE_SF(DP0_DP_MSA_TIMING_PARAM3, DP_MSA_VSYNCPOLARITY, mask_sh),\
|
||||
SE_SF(DP0_DP_MSA_TIMING_PARAM4, DP_MSA_HWIDTH, mask_sh),\
|
||||
SE_SF(DP0_DP_MSA_TIMING_PARAM4, DP_MSA_VHEIGHT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_DB_CONTROL, HDMI_DB_DISABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_VID_TIMING, DP_VID_N_INTERVAL, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FE_CNTL, DIG_SOURCE_SELECT, mask_sh), \
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC2_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC2_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC3_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC3_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC4_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC4_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC5_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC5_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC6_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC6_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC7_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC7_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC8_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC8_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC9_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC9_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC10_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC10_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC11_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC11_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC12_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC12_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC13_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC13_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC14_CONT, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC14_SEND, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL1, HDMI_GENERIC0_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL1, HDMI_GENERIC1_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL2, HDMI_GENERIC2_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL2, HDMI_GENERIC3_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL3, HDMI_GENERIC4_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL3, HDMI_GENERIC5_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL4, HDMI_GENERIC6_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL4, HDMI_GENERIC7_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL7, HDMI_GENERIC8_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL7, HDMI_GENERIC9_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL8, HDMI_GENERIC10_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL8, HDMI_GENERIC11_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL9, HDMI_GENERIC12_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL9, HDMI_GENERIC13_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL10, HDMI_GENERIC14_LINE, mask_sh),\
|
||||
SE_SF(DP0_DP_MSA_VBID_MISC, DP_VBID6_LINE_REFERENCE, mask_sh),\
|
||||
SE_SF(DP0_DP_MSA_VBID_MISC, DP_VBID6_LINE_NUM, mask_sh),\
|
||||
SE_SF(DME0_DME_CONTROL, METADATA_ENGINE_EN, mask_sh),\
|
||||
SE_SF(DME0_DME_CONTROL, METADATA_HUBP_REQUESTOR_ID, mask_sh),\
|
||||
SE_SF(DME0_DME_CONTROL, METADATA_STREAM_TYPE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_METADATA_TRANSMISSION, DP_SEC_METADATA_PACKET_ENABLE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_METADATA_TRANSMISSION, DP_SEC_METADATA_PACKET_LINE_REFERENCE, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_METADATA_TRANSMISSION, DP_SEC_METADATA_PACKET_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_ENABLE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE_REFERENCE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE, mask_sh),\
|
||||
SE_SF(DIG0_HDMI_CONTROL, DOLBY_VISION_EN, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FE_EN_CNTL, DIG_FE_ENABLE, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FE_CLK_CNTL, DIG_FE_MODE, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FE_CLK_CNTL, DIG_FE_CLK_EN, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FE_CLK_CNTL, DIG_FE_SOFT_RESET, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, mask_sh),\
|
||||
SE_SF(DP0_DP_SEC_FRAMING4, DP_SST_SDP_SPLITTING, mask_sh),\
|
||||
SE_SF(DIG0_DIG_CLOCK_PATTERN, DIG_CLOCK_PATTERN, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_OUTPUT_PIXEL_PER_CYCLE, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_READ_START_LEVEL, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_ENABLE, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_RESET, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_RESET_DONE, mask_sh),\
|
||||
SE_SF(DIG0_STREAM_MAPPER_CONTROL, DIG_STREAM_LINK_TARGET, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FE_AUDIO_CNTL, DIG_FE_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, mask_sh),\
|
||||
SE_SF(DIG0_DIG_FE_AUDIO_CNTL, APG_CLOCK_ENABLE, mask_sh),
|
||||
|
||||
void dcn60_dio_stream_encoder_construct(
|
||||
struct dcn10_stream_encoder *enc1,
|
||||
struct dc_context *ctx,
|
||||
struct dc_bios *bp,
|
||||
enum engine_id eng_id,
|
||||
struct vpg *vpg,
|
||||
struct apg *apg,
|
||||
const struct dcn10_stream_enc_registers *regs,
|
||||
const struct dcn10_stream_encoder_shift *se_shift,
|
||||
const struct dcn10_stream_encoder_mask *se_mask);
|
||||
|
||||
#endif /* __DC_DIO_STREAM_ENCODER_DCN60_H__ */
|
||||
@@ -203,6 +203,14 @@ void dm_helpers_mccs_vcp_set(
|
||||
#define EXPORT_IF_KUNIT(symbol)
|
||||
#endif
|
||||
|
||||
bool dm_helpers_submit_i2c_over_aux(
|
||||
struct ddc_service *ddc,
|
||||
uint32_t address,
|
||||
uint8_t offset,
|
||||
uint8_t *cmdBuffer,
|
||||
uint32_t len,
|
||||
bool read);
|
||||
|
||||
bool dm_helpers_dp_handle_test_pattern_request(
|
||||
struct dc_context *ctx,
|
||||
const struct dc_link *link,
|
||||
|
||||
@@ -206,7 +206,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_51_soc = {
|
||||
.sr_enter_plus_exit_time_us = 30.0,
|
||||
.sr_exit_z8_time_us = 263.0,
|
||||
.sr_enter_plus_exit_z8_time_us = 363.0,
|
||||
.fclk_change_latency_us = 24.0,
|
||||
.fclk_change_latency_us = 39.0,
|
||||
.usr_retraining_latency_us = 2,
|
||||
.writeback_latency_us = 12.0,
|
||||
|
||||
@@ -215,7 +215,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_51_soc = {
|
||||
.urgent_latency_pixel_data_only_us = 4.0,
|
||||
.urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
|
||||
.urgent_latency_vm_data_only_us = 4.0,
|
||||
.dram_clock_change_latency_us = 34,
|
||||
.dram_clock_change_latency_us = 39,
|
||||
.urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
|
||||
.urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
|
||||
.urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
|
||||
|
||||
@@ -52,6 +52,9 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dml2_0/dml21/src/dml2_standalo
|
||||
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dml2_0/dml21/src/inc
|
||||
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dml2_0/dml21/inc
|
||||
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dml2_0/dml21/
|
||||
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dml2_0/dml21/inc/bounding_boxes/
|
||||
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dml2_0/dml21/src/dml2_utm_soc_bb/
|
||||
subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dml2_0/dml21/src/dml2_cga/
|
||||
|
||||
# Add FPU flags to all dml2 files by default, remove NO_FPU flags.
|
||||
# FPU flags step 1: Find all .c files in dal/dc/dml2_0 and it's subfolders
|
||||
@@ -107,6 +110,28 @@ DML21 += src/dml2_pmo/dml2_pmo_dcn4_fams2.o
|
||||
DML21 += src/dml2_pmo/dml2_pmo_dcn42.o
|
||||
DML21 += src/dml2_standalone_libraries/lib_float_math.o
|
||||
DML21 += src/dml2_standalone_libraries/lib_frl_cap_check.o
|
||||
DML21 += src/dml2_top/dml2_top_utm.o
|
||||
DML21 += src/dml2_core/dml2_core_dcn5_calcs_dchub.o
|
||||
DML21 += src/dml2_core/dml2_core_dcn5_calcs_display_pipe.o
|
||||
DML21 += src/dml2_core/dml2_core_dcn5_calcs_dsc_latency.o
|
||||
DML21 += src/dml2_core/dml2_core_dcn5_funcs_initialize.o
|
||||
DML21 += src/dml2_core/dml2_core_dcn5_funcs_mode_programming.o
|
||||
DML21 += src/dml2_core/dml2_core_dcn5_funcs_mode_support.o
|
||||
DML21 += src/dml2_dpmm/dml2_dpmm_dcn5.o
|
||||
DML21 += src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn5.o
|
||||
DML21 += src/dml2_utm_soc_bb/dml2_utm_soc_bb_factory.o
|
||||
DML21 += src/dml2_cga/dml2_cga_dcn6.o
|
||||
DML21 += src/dml2_cga/dml2_cga_factory.o
|
||||
DML21 += src/dml2_core/dml2_core_dcn6_calcs_dchub.o
|
||||
DML21 += src/dml2_core/dml2_core_dcn6_funcs_initialize.o
|
||||
DML21 += src/dml2_core/dml2_core_dcn6_funcs_mode_programming.o
|
||||
DML21 += src/dml2_core/dml2_core_dcn6_funcs_mode_support.o
|
||||
DML21 += src/dml2_pmo/dml2_pmo_dcn5.o
|
||||
DML21 += src/dml2_pmo/dml2_pmo_dcn5_stage_optimizers.o
|
||||
DML21 += src/dml2_pmo/dml2_pmo_dcn6.o
|
||||
DML21 += src/dml2_pmo/dml2_pmo_dcn6_stage_optimizers.o
|
||||
DML21 += src/dml2_standalone_libraries/alternate_pstate_shared_lib.o
|
||||
DML21 += src/dml2_utm_soc_bb/dml2_utm_soc_bb_dcn6.o
|
||||
DML21 += dml21_translation_helper.o
|
||||
DML21 += dml21_wrapper.o
|
||||
DML21 += dml21_wrapper_fpu.o
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user