amd-drm-next-7.3-2026-08-19:

amdgpu:
 - eGPU fixes
 - Runtime PM fix
 - UserQ fixes
 - Backlight fix
 - Discovery sysfs fix
 - Reset handling fixes
 - Buffer func handling fix for xgmi
 - VCN boundary check fix
 - DC lut handling fixes
 
 amdkfd:
 - Fix return value
 
 radeon:
 - iMac display fix
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQgO5Idg2tXNTSZAr293/aFa7yZ2AUCaoX2XgAKCRC93/aFa7yZ
 2McyAP45fRlBRPJeNkk5CDWFRFFJXGwmkiKcBAogxFYgzpJ7SAD7BTbXwPGugPPr
 scBCM6qcx8jBH4HSLZnV1gq5tGtcOAc=
 =ayyI
 -----END PGP SIGNATURE-----

Merge tag 'amd-drm-next-7.3-2026-08-19' of https://gitlab.freedesktop.org/agd5f/linux into drm-next

amd-drm-next-7.3-2026-08-19:

amdgpu:
- eGPU fixes
- Runtime PM fix
- UserQ fixes
- Backlight fix
- Discovery sysfs fix
- Reset handling fixes
- Buffer func handling fix for xgmi
- VCN boundary check fix
- DC lut handling fixes

amdkfd:
- Fix return value

radeon:
- iMac display fix

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Alex Deucher <alexander.deucher@amd.com>
Link: https://patch.msgid.link/20260819183622.2406038-1-alexander.deucher@amd.com
This commit is contained in:
Dave Airlie 2026-08-24 09:07:41 +10:00
commit 22e48eeaf4
16 changed files with 160 additions and 74 deletions

View File

@ -609,6 +609,13 @@ void amdgpu_device_detect_runtime_pm_mode(struct amdgpu_device *adev)
int bamaco_support;
adev->pm.rpm_mode = AMDGPU_RUNPM_NONE;
if (pci_is_thunderbolt_attached(adev->pdev) ||
dev_is_removable(&adev->pdev->dev)) {
dev_info(adev->dev,
"Runtime PM disabled for externally attached device\n");
return;
}
bamaco_support = amdgpu_device_supports_baco(adev);
switch (amdgpu_runtime_pm) {
@ -2523,7 +2530,11 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev)
if (r)
goto init_failed;
amdgpu_ttm_enable_buffer_funcs(adev);
/* If SDMA is not brought up during hwini, the ttm buffer funcs enablement
* is delayed after reset-on-init completes.
*/
if (amdgpu_ip_member_of_hwini(adev, AMD_IP_BLOCK_TYPE_SDMA))
amdgpu_ttm_enable_buffer_funcs(adev);
/* Don't init kfd if whole hive need to be reset during init */
if (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI) {
@ -3733,6 +3744,14 @@ static void amdgpu_device_sys_interface_fini(struct amdgpu_device *adev)
amdgpu_ptl_sysfs_fini(adev);
}
static bool
amdgpu_device_should_register_switcheroo(struct amdgpu_device *adev, bool px)
{
return !pci_is_thunderbolt_attached(adev->pdev) &&
(px || (!dev_is_removable(&adev->pdev->dev) &&
apple_gmux_detect(NULL, NULL)));
}
/**
* amdgpu_device_init - initialize the driver
*
@ -4183,8 +4202,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
px = amdgpu_device_supports_px(adev);
if (px || (!dev_is_removable(&adev->pdev->dev) &&
apple_gmux_detect(NULL, NULL)))
if (amdgpu_device_should_register_switcheroo(adev, px))
vga_switcheroo_register_client(adev->pdev,
&amdgpu_switcheroo_ops, px);
@ -4349,8 +4367,7 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
px = amdgpu_device_supports_px(adev);
if (px || (!dev_is_removable(&adev->pdev->dev) &&
apple_gmux_detect(NULL, NULL)))
if (amdgpu_device_should_register_switcheroo(adev, px))
vga_switcheroo_unregister_client(adev->pdev);
if (px)
@ -5037,6 +5054,31 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
amdgpu_fence_driver_force_completion(ring, fence);
}
/*
* MES scheduler rings have no drm scheduler, so they are missed by the
* loop above. Realign their polling fence too (one per XCC), otherwise the
* first post-reset submission polls forever on a stale seq. sched.ready is
* only set while the driver owns the ring.
*/
for (i = 0; i < AMDGPU_MAX_MES_INST_PIPES; i++) {
struct amdgpu_ring *mes_ring = &adev->mes.ring[i];
if (mes_ring->fence_drv.initialized && mes_ring->sched.ready)
amdgpu_fence_driver_force_completion(mes_ring, fence);
}
/*
* KIQ rings are polling-fence/no_scheduler like MES, so realign their
* fence too (one ring per XCC), otherwise the first post-reset KIQ
* submission polls forever on a stale seq.
*/
for (i = 0; i < AMDGPU_MAX_GC_INSTANCES; i++) {
struct amdgpu_ring *kiq_ring = &adev->gfx.kiq[i].ring;
if (kiq_ring->fence_drv.initialized && kiq_ring->sched.ready)
amdgpu_fence_driver_force_completion(kiq_ring, fence);
}
amdgpu_fence_driver_isr_toggle(adev, false);
r = amdgpu_reset_prepare_hwcontext(adev, reset_context);
@ -5137,8 +5179,6 @@ int amdgpu_device_reinit_after_reset(struct amdgpu_reset_context *reset_context)
if (r)
goto out;
amdgpu_ttm_enable_buffer_funcs(tmp_adev);
r = amdgpu_device_ip_resume_phase3(tmp_adev);
if (r)
goto out;

View File

@ -1307,8 +1307,19 @@ static int amdgpu_discovery_sysfs_ips(struct amdgpu_device *adev,
ip_hw_instance->num_instance);
ip_hw_instance->num_base_addresses = ip->num_base_address;
for (kk = 0; kk < ip_hw_instance->num_base_addresses; kk++)
ip_hw_instance->base_addr[kk] = ip->base_address[kk];
for (kk = 0; kk < ip_hw_instance->num_base_addresses; kk++) {
/*
* Standalone mode uses a raw copy of the discovery
* binary; decode 64-bit addresses here. The shared
* bin is already collapsed to 32-bit in place.
*/
if (reg_base_64 && ip_top->standalone_mode)
ip_hw_instance->base_addr[kk] =
lower_32_bits(le64_to_cpu(ip->base_address_64[kk])) & 0x3FFFFFFF;
else
ip_hw_instance->base_addr[kk] =
le32_to_cpu(ip->base_address[kk]);
}
kobject_init(&ip_hw_instance->kobj, &ip_hw_instance_ktype);
ip_hw_instance->kobj.kset = &ip_hw_id->hw_id_kset;

View File

@ -2557,6 +2557,7 @@ amdgpu_pci_remove(struct pci_dev *pdev)
if (adev->pm.rpm_mode != AMDGPU_RUNPM_NONE) {
pm_runtime_get_sync(dev->dev);
pm_runtime_forbid(dev->dev);
pm_runtime_dont_use_autosuspend(dev->dev);
}
amdgpu_driver_unload_kms(dev);

View File

@ -222,7 +222,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
vm_af = job->hw_vm_fence;
/* VM sequence */
vm_af->ib_wptr = ring->wptr;
amdgpu_vm_flush(ring, job, need_pipe_sync, &emit_spm_needed,
amdgpu_vm_flush(ring, job, &need_pipe_sync, &emit_spm_needed,
&emit_gds_needed);
vm_af->ib_dw_size =
amdgpu_ring_get_dw_distance(ring, vm_af->ib_wptr, ring->wptr);
@ -235,6 +235,10 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
if (ring->funcs->insert_start)
ring->funcs->insert_start(ring);
/* this may have been handled by amdgpu_vm_flush */
if (need_pipe_sync)
amdgpu_ring_emit_pipeline_sync(ring);
if (emit_spm_needed)
adev->gfx.rlc.funcs->update_spm_vmid(adev, ring->xcc_id, ring, job->vmid);

View File

@ -287,22 +287,24 @@ static bool amdgpu_userq_buffer_va_mapped(struct amdgpu_vm *vm, u64 addr)
static bool amdgpu_userq_buffer_vas_mapped(struct amdgpu_usermode_queue *queue)
{
int i, r = 0;
int i;
bool mapped;
for (i = 0; i < ARRAY_SIZE(queue->userq_vas.va_array); i++) {
if (!queue->userq_vas.va_array[i])
continue;
r += amdgpu_userq_buffer_va_mapped(queue->vm,
mapped = amdgpu_userq_buffer_va_mapped(queue->vm,
queue->userq_vas.va_array[i]);
dev_dbg(queue->userq_mgr->adev->dev,
"validate the userq mapping:%p va:%llx r:%d\n",
queue, queue->userq_vas.va_array[i], r);
queue, queue->userq_vas.va_array[i], mapped);
if (!mapped)
return false;
}
if (r != 0)
return true;
return false;
return true;
}
@ -416,19 +418,12 @@ static void amdgpu_userq_wait_for_last_fence(struct amdgpu_usermode_queue *queue
dma_fence_wait(f, false);
}
static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue)
static void amdgpu_userq_detach_doorbell(struct amdgpu_usermode_queue *queue)
{
struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
struct amdgpu_device *adev = uq_mgr->adev;
struct amdgpu_device *adev = queue->userq_mgr->adev;
/* Wait for mode-1 reset to complete */
down_read(&adev->reset_domain->sem);
/* Use interrupt-safe locking since IRQ handlers may access these XArrays */
xa_erase_irq(&adev->userq_doorbell_xa, queue->doorbell_index);
amdgpu_userq_fence_driver_free(queue);
queue->fence_drv = NULL;
up_read(&adev->reset_domain->sem);
}
@ -549,18 +544,19 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
cancel_delayed_work_sync(&uq_mgr->resume_work);
/* Cancel any pending hang detection work and cleanup */
cancel_delayed_work_sync(&queue->hang_detect_work);
mutex_lock(&uq_mgr->userq_mutex);
amdgpu_userq_wait_for_last_fence(queue);
amdgpu_userq_detach_doorbell(queue);
cancel_delayed_work_sync(&queue->hang_detect_work);
#if defined(CONFIG_DEBUG_FS)
debugfs_remove_recursive(queue->debugfs_queue);
#endif
r = amdgpu_userq_unmap_helper(queue);
atomic_dec(&uq_mgr->userq_count[queue->queue_type]);
amdgpu_userq_cleanup(queue);
amdgpu_userq_fence_driver_free(queue);
queue->fence_drv = NULL;
mutex_unlock(&uq_mgr->userq_mutex);
/*
@ -572,7 +568,6 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que
if (r)
queue_work(adev->reset_domain->wq, &uq_mgr->reset_work);
cancel_delayed_work_sync(&queue->hang_detect_work);
uq_funcs->mqd_destroy(queue);
queue->userq_mgr = NULL;
@ -700,10 +695,10 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
args->in.queue_size,
&queue->userq_vas.va.queue_rb) ||
amdgpu_userq_input_va_validate(adev, queue, args->in.rptr_va,
AMDGPU_GPU_PAGE_SIZE,
sizeof(u64),
&queue->userq_vas.va.rptr) ||
amdgpu_userq_input_va_validate(adev, queue, args->in.wptr_va,
AMDGPU_GPU_PAGE_SIZE,
sizeof(u64),
&queue->userq_vas.va.wptr)) {
r = -EINVAL;
amdgpu_bo_unreserve(fpriv->vm.root.bo);
@ -746,7 +741,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
((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().
* unresponsive during recovery), matching amdgpu_userq_detach_doorbell().
*/
down_read(&adev->reset_domain->sem);
r = amdgpu_userq_map_helper(queue);
@ -848,6 +843,12 @@ static int amdgpu_userq_input_args_validate(struct drm_device *dev,
drm_file_err(filp, "invalidate userq queue rptr or wptr\n");
return -EINVAL;
}
if (!IS_ALIGNED(args->in.wptr_va, sizeof(u64)) ||
!IS_ALIGNED(args->in.rptr_va, sizeof(u64))) {
drm_file_err(filp, "user queue rptr or wptr is not 8-byte aligned\n");
return -EINVAL;
}
break;
case AMDGPU_USERQ_OP_FREE:
if (args->in.ip_type ||

View File

@ -537,7 +537,7 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
* amdgpu_userq_ensure_ev_fence() can't be called while holding the resv
* locks.
*/
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT,
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES,
(num_read_bo_handles + num_write_bo_handles));
drm_exec_until_all_locked(&exec) {
@ -643,7 +643,7 @@ amdgpu_userq_wait_count_fences(struct drm_file *filp,
/* TODO: It is actually not necessary to lock them */
num_read_bo_handles = wait_info->num_bo_read_handles;
num_write_bo_handles = wait_info->num_bo_write_handles;
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT,
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES,
num_read_bo_handles + num_write_bo_handles);
drm_exec_until_all_locked(&exec) {
@ -778,7 +778,7 @@ amdgpu_userq_wait_return_fence_info(struct drm_device *dev, struct drm_file *fil
/* Lock all the GEM objects */
num_read_bo_handles = wait_info->num_bo_read_handles;
num_write_bo_handles = wait_info->num_bo_write_handles;
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT,
drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES,
num_read_bo_handles + num_write_bo_handles);
drm_exec_until_all_locked(&exec) {

View File

@ -772,7 +772,7 @@ bool amdgpu_vm_need_pipeline_sync(struct amdgpu_ring *ring,
* Emit a VM flush when it is necessary.
*/
void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
bool need_pipe_sync, bool *emit_spm_needed,
bool *need_pipe_sync, bool *emit_spm_needed,
bool *emit_gds_needed)
{
struct amdgpu_device *adev = ring->adev;
@ -827,8 +827,7 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
if (gds_switch_needed && emit_fence)
*emit_gds_needed = false;
if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync &&
!cleaner_shader_needed && !spm_update_needed)
if (!emit_fence)
return;
amdgpu_ring_ib_begin(ring);
@ -847,8 +846,10 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
patch = amdgpu_ring_init_cond_exec(ring,
ring->cond_exe_gpu_addr);
if (need_pipe_sync)
if (*need_pipe_sync) {
amdgpu_ring_emit_pipeline_sync(ring);
*need_pipe_sync = false;
}
if (cleaner_shader_needed)
ring->funcs->emit_cleaner_shader(ring);
@ -861,21 +862,19 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
if (pasid_mapping_needed)
amdgpu_gmc_emit_pasid_mapping(ring, job->vmid, job->pasid);
if (emit_fence) {
if (spm_update_needed)
adev->gfx.rlc.funcs->update_spm_vmid(adev, ring->xcc_id, ring, job->vmid);
if (spm_update_needed)
adev->gfx.rlc.funcs->update_spm_vmid(adev, ring->xcc_id, ring, job->vmid);
if (gds_switch_needed)
amdgpu_ring_emit_gds_switch(ring, job->vmid, job->gds_base,
if (gds_switch_needed)
amdgpu_ring_emit_gds_switch(ring, job->vmid, job->gds_base,
job->gds_size, job->gws_base,
job->gws_size, job->oa_base,
job->oa_size);
amdgpu_fence_emit(ring, job->hw_vm_fence, 0);
fence = &job->hw_vm_fence->base;
/* get a ref for the job */
dma_fence_get(fence);
}
amdgpu_fence_emit(ring, job->hw_vm_fence, 0);
fence = &job->hw_vm_fence->base;
/* get a ref for the job */
dma_fence_get(fence);
if (vm_flush_needed) {
mutex_lock(&id_mgr->lock);

View File

@ -512,7 +512,7 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm,
int (*callback)(void *p, struct amdgpu_bo *bo),
void *param);
void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job,
bool need_pipe_sync, bool *emit_spm_needed,
bool *need_pipe_sync, bool *emit_spm_needed,
bool *emit_gds_needed);
int amdgpu_vm_update_pdes(struct amdgpu_device *adev,
struct amdgpu_vm *vm, bool immediate);

View File

@ -1380,6 +1380,9 @@ static void amdgpu_xgmi_reset_on_init_work(struct work_struct *work)
amdgpu_device_unlock_reset_domain(tmp_adev->reset_domain);
list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) {
/* Enable ttm buffers funcs after the reset lock has been dropped. */
amdgpu_ttm_enable_buffer_funcs(tmp_adev);
r = amdgpu_ras_init_badpage_info(tmp_adev);
if (r && r != -EHWPOISON)
dev_err(tmp_adev->dev,

View File

@ -1964,9 +1964,13 @@ static int vcn_v3_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
len_dw = msg[1] / 4;
num_buffers = msg[2];
/* Verify that all indices fit within the claimed length. Each index is 4 DWORDs */
if (num_buffers > len_dw || 6 + num_buffers * 4 > len_dw) {
DRM_ERROR("VCN message has too many buffers!\n");
/* Verify that all indices fit within the claimed length.
* There are 6 dwords in the header before the first buffer.
* Each buffer has 4 dwords. Any trailing dwords after the
* last buffer are ignored.
*/
if (len_dw < 6 || num_buffers > (len_dw - 6) / 4) {
DRM_ERROR("Invalid VCN message!\n");
r = -EINVAL;
goto out;
}

View File

@ -1880,9 +1880,13 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job,
len_dw = msg[1] / 4;
num_buffers = msg[2];
/* Verify that all indices fit within the claimed length. Each index is 4 DWORDs */
if (num_buffers > len_dw || 6 + num_buffers * 4 > len_dw) {
DRM_ERROR("VCN message has too many buffers!\n");
/* Verify that all indices fit within the claimed length.
* There are 6 dwords in the header before the first buffer.
* Each buffer has 4 dwords. Any trailing dwords after the
* last buffer are ignored.
*/
if (len_dw < 6 || num_buffers > (len_dw - 6) / 4) {
DRM_ERROR("Invalid VCN message!\n");
r = -EINVAL;
goto out;
}

View File

@ -3329,7 +3329,7 @@ static int kfd_ioctl_create_process(struct file *filep, struct kfd_process *p, v
return 0;
}
static inline uint32_t profile_lock_device(struct kfd_process *p,
static inline int profile_lock_device(struct kfd_process *p,
uint32_t gpu_id, uint32_t op)
{
struct kfd_process_device *pdd;

View File

@ -106,10 +106,10 @@ int get_brightness_range(const struct amdgpu_dm_backlight_caps *caps,
}
EXPORT_IF_KUNIT(get_brightness_range);
/* Rescale from [min..max] to [0..AMDGPU_MAX_BL_LEVEL] */
static inline u32 scale_input_to_fw(int min, int max, u64 input)
/* Rescale userspace [0..max] to the firmware curve's [0..255]. */
static inline u32 scale_input_to_fw(int max, u64 input)
{
return DIV_ROUND_CLOSEST_ULL(input * AMDGPU_MAX_BL_LEVEL, max - min);
return DIV_ROUND_CLOSEST_ULL(input * AMDGPU_MAX_BL_LEVEL, max);
}
/* Rescale from [0..AMDGPU_MAX_BL_LEVEL] to [min..max] */
@ -123,7 +123,7 @@ void convert_custom_brightness(const struct amdgpu_dm_backlight_caps *caps,
unsigned int min, unsigned int max,
uint32_t *user_brightness)
{
u32 brightness = scale_input_to_fw(min, max, *user_brightness);
u32 brightness = scale_input_to_fw(max, *user_brightness);
u8 lower_signal, upper_signal, upper_lum, lower_lum, lum;
int left, right;

View File

@ -471,6 +471,12 @@ bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size)
uint32_t expected;
int delta;
/* A LUT with fewer than two entries can't be interpolated and would
* divide by zero below (size - 1); it can't be treated as linear.
*/
if (size < 2)
return false;
for (i = 0; i < size; i++) {
/* All color values should equal */
if ((lut[i].red != lut[i].green) || (lut[i].green != lut[i].blue))
@ -1489,6 +1495,13 @@ __set_dm_plane_degamma(struct drm_plane_state *plane_state,
degamma_lut = __extract_blob_lut(dm_plane_state->degamma_lut,
&degamma_size);
if (degamma_lut && degamma_size != MAX_COLOR_LUT_ENTRIES) {
drm_dbg(plane_state->state->dev,
"Invalid Plane Degamma LUT size. Should be %u but got %u.\n",
MAX_COLOR_LUT_ENTRIES, degamma_size);
return -EINVAL;
}
has_degamma_lut = degamma_lut &&
!__is_lut_linear(degamma_lut, degamma_size);

View File

@ -24,6 +24,8 @@
* Alex Deucher
*/
#include <linux/dmi.h>
#include <drm/drm_fixed.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
@ -594,7 +596,8 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
if (((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880))
&& !radeon_crtc->ss_enabled)
radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
if (ASIC_IS_DCE32(rdev) && mode->clock > 165000)
if ((ASIC_IS_DCE32(rdev) || dmi_match(DMI_PRODUCT_NAME, "iMac11,1"))
&& mode->clock > 165000)
radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
} else {
radeon_crtc->pll_flags |= RADEON_PLL_LEGACY;

View File

@ -1707,7 +1707,7 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) {
/* DP_SET_POWER_D0 is set in radeon_dp_link_train */
radeon_dp_link_train(encoder, connector);
if (ASIC_IS_DCE4(rdev))
if (ASIC_IS_DCE4(rdev) || dmi_match(DMI_PRODUCT_NAME, "iMac11,1"))
atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);
}
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
@ -2123,17 +2123,20 @@ int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx)
}
/*
* On DCE32 any encoder can drive any block so usually just use crtc id,
* but Apple thinks different at least on iMac10,1 and iMac11,2, so there use linkb,
* otherwise the internal eDP panel will stay dark.
* Apple routes the internal eDP panel through Link B of the DIG encoder
* instead of Link A on the iMac10,1, iMac11,1 and iMac11,2.
* Use linkb to avoid a dark display.
*/
if (ASIC_IS_DCE32(rdev)) {
if (dmi_match(DMI_PRODUCT_NAME, "iMac10,1") ||
dmi_match(DMI_PRODUCT_NAME, "iMac11,2"))
enc_idx = (dig->linkb) ? 1 : 0;
else
enc_idx = radeon_crtc->crtc_id;
if (dmi_match(DMI_PRODUCT_NAME, "iMac10,1") ||
dmi_match(DMI_PRODUCT_NAME, "iMac11,1") ||
dmi_match(DMI_PRODUCT_NAME, "iMac11,2")) {
enc_idx = (dig->linkb) ? 1 : 0;
goto assigned;
}
/* on DCE32 and encoder can driver any block so just crtc id */
if (ASIC_IS_DCE32(rdev)) {
enc_idx = radeon_crtc->crtc_id;
goto assigned;
}