/* * Copyright 2007-8 Advanced Micro Devices, Inc. * Copyright 2008 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Dave Airlie * Alex Deucher */#include <drm/drmP.h>#include <drm/amdgpu_drm.h>#include "amdgpu.h"#include "amdgpu_i2c.h"#include "atom.h"#include "amdgpu_connectors.h"#include <asm/div64.h> #include <linux/pm_runtime.h>#include <drm/drm_crtc_helper.h>#include <drm/drm_edid.h> static void amdgpu_flip_work_func(struct work_struct *__work){ struct amdgpu_flip_work *work = container_of(__work, struct amdgpu_flip_work, flip_work); struct amdgpu_device *adev = work->adev; struct amdgpu_crtc *amdgpuCrtc = adev->mode_info.crtcs[work->crtc_id]; struct drm_crtc *crtc = &amdgpuCrtc->base; struct amdgpu_fence *fence; unsigned long flags; int r; down_read(&adev->exclusive_lock); if (work->fence) { fence = to_amdgpu_fence(work->fence); if (fence) { r = amdgpu_fence_wait(fence, false); if (r == -EDEADLK) { up_read(&adev->exclusive_lock); r = amdgpu_gpu_reset(adev); down_read(&adev->exclusive_lock); } } else r = fence_wait(work->fence, false); if (r) DRM_ERROR("failed to wait on page flip fence (%d)!\n", r); /* We continue with the page flip even if we failed to wait on * the fence, otherwise the DRM core and userspace will be * confused about which BO the CRTC is scanning out */ fence_put(work->fence); work->fence = NULL; } /* We borrow the event spin lock for protecting flip_status */ spin_lock_irqsave(&crtc->dev->event_lock, flags); /* set the proper interrupt */ amdgpu_irq_get(adev, &adev->pageflip_irq, work->crtc_id); /* do the flip (mmio) */ adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base); /* set the flip status */ amdgpuCrtc->pflip_status = AMDGPU_FLIP_SUBMITTED; spin_unlock_irqrestore(&crtc->dev->event_lock, flags); up_read(&adev->exclusive_lock);} /* * Handle unpin events outside the interrupt handler proper. */static void amdgpu_unpin_work_func(struct work_struct *__work){ struct amdgpu_flip_work *work = container_of(__work, struct amdgpu_flip_work, unpin_work); int r; /* unpin of the old buffer */ r = amdgpu_bo_reserve(work->old_rbo, false); if (likely(r == 0)) { r = amdgpu_bo_unpin(work->old_rbo); if (unlikely(r != 0)) { DRM_ERROR("failed to unpin buffer after flip\n"); } amdgpu_bo_unreserve(work->old_rbo); } else DRM_ERROR("failed to reserve buffer after flip\n"); drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base); kfree(work);} int amdgpu_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags){ struct drm_device *dev = crtc->dev; struct amdgpu_device *adev = dev->dev_private; struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct amdgpu_framebuffer *old_amdgpu_fb; struct amdgpu_framebuffer *new_amdgpu_fb; struct drm_gem_object *obj; struct amdgpu_flip_work *work; struct amdgpu_bo *new_rbo; unsigned long flags; u64 tiling_flags; u64 base; int r; work = kzalloc(sizeof *work, GFP_KERNEL); if (work == NULL) return -ENOMEM; INIT_WORK(&work->flip_work, amdgpu_flip_work_func); INIT_WORK(&work->unpin_work, amdgpu_unpin_work_func); work->event = event; work->adev = adev; work->crtc_id = amdgpu_crtc->crtc_id; /* schedule unpin of the old buffer */ old_amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb); obj = old_amdgpu_fb->obj; /* take a reference to the old object */ drm_gem_object_reference(obj); work->old_rbo = gem_to_amdgpu_bo(obj); new_amdgpu_fb = to_amdgpu_framebuffer(fb); obj = new_amdgpu_fb->obj; new_rbo = gem_to_amdgpu_bo(obj); /* pin the new buffer */ r = amdgpu_bo_reserve(new_rbo, false); if (unlikely(r != 0)) { DRM_ERROR("failed to reserve new rbo buffer before flip\n"); goto cleanup; } r = amdgpu_bo_pin_restricted(new_rbo, AMDGPU_GEM_DOMAIN_VRAM, 0, 0, &base); if (unlikely(r != 0)) { amdgpu_bo_unreserve(new_rbo); r = -EINVAL; DRM_ERROR("failed to pin new rbo buffer before flip\n"); goto cleanup; } work->fence = fence_get(reservation_object_get_excl(new_rbo->tbo.resv)); amdgpu_bo_get_tiling_flags(new_rbo, &tiling_flags); amdgpu_bo_unreserve(new_rbo); work->base = base; r = drm_vblank_get(crtc->dev, amdgpu_crtc->crtc_id); if (r) { DRM_ERROR("failed to get vblank before flip\n"); goto pflip_cleanup; } /* we borrow the event spin lock for protecting flip_wrok */ spin_lock_irqsave(&crtc->dev->event_lock, flags); if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_NONE) { DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); spin_unlock_irqrestore(&crtc->dev->event_lock, flags); r = -EBUSY; goto vblank_cleanup; } amdgpu_crtc->pflip_status = AMDGPU_FLIP_PENDING; amdgpu_crtc->pflip_works = work; /* update crtc fb */ crtc->primary->fb = fb; spin_unlock_irqrestore(&crtc->dev->event_lock, flags); queue_work(amdgpu_crtc->pflip_queue, &work->flip_work); return 0; vblank_cleanup: drm_vblank_put(crtc->dev, amdgpu_crtc->crtc_id); pflip_cleanup: if (unlikely(amdgpu_bo_reserve(new_rbo, false) != 0)) { DRM_ERROR("failed to reserve new rbo in error path\n"); goto cleanup; } if (unlikely(amdgpu_bo_unpin(new_rbo) != 0)) { DRM_ERROR("failed to unpin new rbo in error path\n"); } amdgpu_bo_unreserve(new_rbo); cleanup: drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base); fence_put(work->fence); kfree(work); return r;} int amdgpu_crtc_set_config(struct drm_mode_set *set){ struct drm_device *dev; struct amdgpu_device *adev; struct drm_crtc *crtc; bool active = false; int ret; if (!set || !set->crtc) return -EINVAL; dev = set->crtc->dev; ret = pm_runtime_get_sync(dev->dev); if (ret < 0) return ret; ret = drm_crtc_helper_set_config(set); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) if (crtc->enabled) active = true; pm_runtime_mark_last_busy(dev->dev); adev = dev->dev_private; /* if we have active crtcs and we don't have a power ref, take the current one */ if (active && !adev->have_disp_power_ref) { adev->have_disp_power_ref = true; return ret; } /* if we have no active crtcs, then drop the power ref we got before */ if (!active && adev->have_disp_power_ref) { pm_runtime_put_autosuspend(dev->dev); adev->have_disp_power_ref = false; } /* drop the power reference we got coming in here */ pm_runtime_put_autosuspend(dev->dev); return ret;} static const char *encoder_names[38] = { "NONE", "INTERNAL_LVDS", "INTERNAL_TMDS1", "INTERNAL_TMDS2", "INTERNAL_DAC1", "INTERNAL_DAC2", "INTERNAL_SDVOA", "INTERNAL_SDVOB", "SI170B", "CH7303", "CH7301", "INTERNAL_DVO1", "EXTERNAL_SDVOA", "EXTERNAL_SDVOB", "TITFP513", "INTERNAL_LVTM1", "VT1623", "HDMI_SI1930", "HDMI_INTERNAL", "INTERNAL_KLDSCP_TMDS1", "INTERNAL_KLDSCP_DVO1", "INTERNAL_KLDSCP_DAC1", "INTERNAL_KLDSCP_DAC2", "SI178", "MVPU_FPGA", "INTERNAL_DDI", "VT1625", "HDMI_SI1932", "DP_AN9801", "DP_DP501", "INTERNAL_UNIPHY", "INTERNAL_KLDSCP_LVTMA", "INTERNAL_UNIPHY1", "INTERNAL_UNIPHY2", "NUTMEG", "TRAVIS", "INTERNAL_VCE", "INTERNAL_UNIPHY3",}; static const char *hpd_names[6] = { "HPD1", "HPD2", "HPD3", "HPD4", "HPD5", "HPD6",}; void amdgpu_print_display_setup(struct drm_device *dev){ struct drm_connector *connector; struct amdgpu_connector *amdgpu_connector; struct drm_encoder *encoder; struct amdgpu_encoder *amdgpu_encoder; uint32_t devices; int i = 0; DRM_INFO("AMDGPU Display Connectors\n"); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { amdgpu_connector = to_amdgpu_connector(connector); DRM_INFO("Connector %d:\n", i); DRM_INFO(" %s\n", connector->name); if (amdgpu_connector->hpd.hpd != AMDGPU_HPD_NONE) DRM_INFO(" %s\n", hpd_names[amdgpu_connector->hpd.hpd]); if (amdgpu_connector->ddc_bus) { DRM_INFO(" DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", amdgpu_connector->ddc_bus->rec.mask_clk_reg, amdgpu_connector->ddc_bus->rec.mask_data_reg, amdgpu_connector->ddc_bus->rec.a_clk_reg, amdgpu_connector->ddc_bus->rec.a_data_reg, amdgpu_connector->ddc_bus->rec.en_clk_reg, amdgpu_connector->ddc_bus->rec.en_data_reg, amdgpu_connector->ddc_bus->rec.y_clk_reg, amdgpu_connector->ddc_bus->rec.y_data_reg); if (amdgpu_connector->router.ddc_valid) DRM_INFO(" DDC Router 0x%x/0x%x\n", amdgpu_connector->router.ddc_mux_control_pin, amdgpu_connector->router.ddc_mux_state); if (amdgpu_connector->router.cd_valid) DRM_INFO(" Clock/Data Router 0x%x/0x%x\n", amdgpu_connector->router.cd_mux_control_pin, amdgpu_connector->router.cd_mux_state); } else { if (connector->connector_type == DRM_MODE_CONNECTOR_VGA || connector->connector_type == DRM_MODE_CONNECTOR_DVII || connector->connector_type == DRM_MODE_CONNECTOR_DVID || connector->connector_type == DRM_MODE_CONNECTOR_DVIA || connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) DRM_INFO(" DDC: no ddc bus - possible BIOS bug - please report to xorg-driver-ati@lists.x.org\n"); } DRM_INFO(" Encoders:\n"); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { amdgpu_encoder = to_amdgpu_encoder(encoder); devices = amdgpu_encoder->devices & amdgpu_connector->devices; if (devices) { if (devices & ATOM_DEVICE_CRT1_SUPPORT) DRM_INFO(" CRT1: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_CRT2_SUPPORT) DRM_INFO(" CRT2: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_LCD1_SUPPORT) DRM_INFO(" LCD1: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_DFP1_SUPPORT) DRM_INFO(" DFP1: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_DFP2_SUPPORT) DRM_INFO(" DFP2: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_DFP3_SUPPORT) DRM_INFO(" DFP3: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_DFP4_SUPPORT) DRM_INFO(" DFP4: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_DFP5_SUPPORT) DRM_INFO(" DFP5: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_DFP6_SUPPORT) DRM_INFO(" DFP6: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_TV1_SUPPORT) DRM_INFO(" TV1: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_CV_SUPPORT) DRM_INFO(" CV: %s\n", encoder_names[amdgpu_encoder->encoder_id]); } } i++; }} /** * amdgpu_ddc_probe * */bool amdgpu_ddc_probe(struct amdgpu_connector *amdgpu_connector, bool use_aux){ u8 out = 0x0; u8 buf[8]; int ret; struct i2c_msg msgs[] = { { .addr = DDC_ADDR, .flags = 0, .len = 1, .buf = &out, }, { .addr = DDC_ADDR, .flags = I2C_M_RD, .len = 8, .buf = buf, } }; /* on hw with routers, select right port */ if (amdgpu_connector->router.ddc_valid) amdgpu_i2c_router_select_ddc_port(amdgpu_connector); if (use_aux) { ret = i2c_transfer(&amdgpu_connector->ddc_bus->aux.ddc, msgs, 2); } else { ret = i2c_transfer(&amdgpu_connector->ddc_bus->adapter, msgs, 2); } if (ret != 2) /* Couldn't find an accessible DDC on this connector */ return false; /* Probe also for valid EDID header * EDID header starts with: * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00. * Only the first 6 bytes must be valid as * drm_edid_block_valid() can fix the last 2 bytes */ if (drm_edid_header_is_valid(buf) < 6) { /* Couldn't find an accessible EDID on this * connector */ return false; } return true;} static void amdgpu_user_framebuffer_destroy(struct drm_framebuffer *fb){ struct amdgpu_framebuffer *amdgpu_fb = to_amdgpu_framebuffer(fb); if (amdgpu_fb->obj) { drm_gem_object_unreference_unlocked(amdgpu_fb->obj); } drm_framebuffer_cleanup(fb); kfree(amdgpu_fb);} static int amdgpu_user_framebuffer_create_handle(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned int *handle){ struct amdgpu_framebuffer *amdgpu_fb = to_amdgpu_framebuffer(fb); return drm_gem_handle_create(file_priv, amdgpu_fb->obj, handle);} static const struct drm_framebuffer_funcs amdgpu_fb_funcs = { .destroy = amdgpu_user_framebuffer_destroy, .create_handle = amdgpu_user_framebuffer_create_handle,}; intamdgpu_framebuffer_init(struct drm_device *dev, struct amdgpu_framebuffer *rfb, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj){ int ret; rfb->obj = obj; drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd); ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs); if (ret) { rfb->obj = NULL; return ret; } return 0;} static struct drm_framebuffer *amdgpu_user_framebuffer_create(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd){ struct drm_gem_object *obj; struct amdgpu_framebuffer *amdgpu_fb; int ret; obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); if (obj == NULL) { dev_err(&dev->pdev->dev, "No GEM object associated to handle 0x%08X, " "can't create framebuffer\n", mode_cmd->handles[0]); return ERR_PTR(-ENOENT); } amdgpu_fb = kzalloc(sizeof(*amdgpu_fb), GFP_KERNEL);Lines 1–500 of 832. Load more
/* * Copyright 2007-8 Advanced Micro Devices, Inc. * Copyright 2008 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Dave Airlie * Alex Deucher */ #include <drm/drmP.h> #include <drm/amdgpu_drm.h> #include "amdgpu.h" #include "amdgpu_i2c.h" #include "atom.h" #include "amdgpu_connectors.h" #include <asm/div64.h> #include <linux/pm_runtime.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> static void amdgpu_flip_work_func(struct work_struct *__work) { struct amdgpu_flip_work *work = container_of(__work, struct amdgpu_flip_work, flip_work); struct amdgpu_device *adev = work->adev; struct amdgpu_crtc *amdgpuCrtc = adev->mode_info.crtcs[work->crtc_id]; struct drm_crtc *crtc = &amdgpuCrtc->base; struct amdgpu_fence *fence; unsigned long flags; int r; down_read(&adev->exclusive_lock); if (work->fence) { fence = to_amdgpu_fence(work->fence); if (fence) { r = amdgpu_fence_wait(fence, false); if (r == -EDEADLK) { up_read(&adev->exclusive_lock); r = amdgpu_gpu_reset(adev); down_read(&adev->exclusive_lock); } } else r = fence_wait(work->fence, false); if (r) DRM_ERROR("failed to wait on page flip fence (%d)!\n", r); /* We continue with the page flip even if we failed to wait on * the fence, otherwise the DRM core and userspace will be * confused about which BO the CRTC is scanning out */ fence_put(work->fence); work->fence = NULL; } /* We borrow the event spin lock for protecting flip_status */ spin_lock_irqsave(&crtc->dev->event_lock, flags); /* set the proper interrupt */ amdgpu_irq_get(adev, &adev->pageflip_irq, work->crtc_id); /* do the flip (mmio) */ adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base); /* set the flip status */ amdgpuCrtc->pflip_status = AMDGPU_FLIP_SUBMITTED; spin_unlock_irqrestore(&crtc->dev->event_lock, flags); up_read(&adev->exclusive_lock); } /* * Handle unpin events outside the interrupt handler proper. */ static void amdgpu_unpin_work_func(struct work_struct *__work) { struct amdgpu_flip_work *work = container_of(__work, struct amdgpu_flip_work, unpin_work); int r; /* unpin of the old buffer */ r = amdgpu_bo_reserve(work->old_rbo, false); if (likely(r == 0)) { r = amdgpu_bo_unpin(work->old_rbo); if (unlikely(r != 0)) { DRM_ERROR("failed to unpin buffer after flip\n"); } amdgpu_bo_unreserve(work->old_rbo); } else DRM_ERROR("failed to reserve buffer after flip\n"); drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base); kfree(work); } int amdgpu_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags) { struct drm_device *dev = crtc->dev; struct amdgpu_device *adev = dev->dev_private; struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); struct amdgpu_framebuffer *old_amdgpu_fb; struct amdgpu_framebuffer *new_amdgpu_fb; struct drm_gem_object *obj; struct amdgpu_flip_work *work; struct amdgpu_bo *new_rbo; unsigned long flags; u64 tiling_flags; u64 base; int r; work = kzalloc(sizeof *work, GFP_KERNEL); if (work == NULL) return -ENOMEM; INIT_WORK(&work->flip_work, amdgpu_flip_work_func); INIT_WORK(&work->unpin_work, amdgpu_unpin_work_func); work->event = event; work->adev = adev; work->crtc_id = amdgpu_crtc->crtc_id; /* schedule unpin of the old buffer */ old_amdgpu_fb = to_amdgpu_framebuffer(crtc->primary->fb); obj = old_amdgpu_fb->obj; /* take a reference to the old object */ drm_gem_object_reference(obj); work->old_rbo = gem_to_amdgpu_bo(obj); new_amdgpu_fb = to_amdgpu_framebuffer(fb); obj = new_amdgpu_fb->obj; new_rbo = gem_to_amdgpu_bo(obj); /* pin the new buffer */ r = amdgpu_bo_reserve(new_rbo, false); if (unlikely(r != 0)) { DRM_ERROR("failed to reserve new rbo buffer before flip\n"); goto cleanup; } r = amdgpu_bo_pin_restricted(new_rbo, AMDGPU_GEM_DOMAIN_VRAM, 0, 0, &base); if (unlikely(r != 0)) { amdgpu_bo_unreserve(new_rbo); r = -EINVAL; DRM_ERROR("failed to pin new rbo buffer before flip\n"); goto cleanup; } work->fence = fence_get(reservation_object_get_excl(new_rbo->tbo.resv)); amdgpu_bo_get_tiling_flags(new_rbo, &tiling_flags); amdgpu_bo_unreserve(new_rbo); work->base = base; r = drm_vblank_get(crtc->dev, amdgpu_crtc->crtc_id); if (r) { DRM_ERROR("failed to get vblank before flip\n"); goto pflip_cleanup; } /* we borrow the event spin lock for protecting flip_wrok */ spin_lock_irqsave(&crtc->dev->event_lock, flags); if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_NONE) { DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); spin_unlock_irqrestore(&crtc->dev->event_lock, flags); r = -EBUSY; goto vblank_cleanup; } amdgpu_crtc->pflip_status = AMDGPU_FLIP_PENDING; amdgpu_crtc->pflip_works = work; /* update crtc fb */ crtc->primary->fb = fb; spin_unlock_irqrestore(&crtc->dev->event_lock, flags); queue_work(amdgpu_crtc->pflip_queue, &work->flip_work); return 0; vblank_cleanup: drm_vblank_put(crtc->dev, amdgpu_crtc->crtc_id); pflip_cleanup: if (unlikely(amdgpu_bo_reserve(new_rbo, false) != 0)) { DRM_ERROR("failed to reserve new rbo in error path\n"); goto cleanup; } if (unlikely(amdgpu_bo_unpin(new_rbo) != 0)) { DRM_ERROR("failed to unpin new rbo in error path\n"); } amdgpu_bo_unreserve(new_rbo); cleanup: drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base); fence_put(work->fence); kfree(work); return r; } int amdgpu_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; struct amdgpu_device *adev; struct drm_crtc *crtc; bool active = false; int ret; if (!set || !set->crtc) return -EINVAL; dev = set->crtc->dev; ret = pm_runtime_get_sync(dev->dev); if (ret < 0) return ret; ret = drm_crtc_helper_set_config(set); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) if (crtc->enabled) active = true; pm_runtime_mark_last_busy(dev->dev); adev = dev->dev_private; /* if we have active crtcs and we don't have a power ref, take the current one */ if (active && !adev->have_disp_power_ref) { adev->have_disp_power_ref = true; return ret; } /* if we have no active crtcs, then drop the power ref we got before */ if (!active && adev->have_disp_power_ref) { pm_runtime_put_autosuspend(dev->dev); adev->have_disp_power_ref = false; } /* drop the power reference we got coming in here */ pm_runtime_put_autosuspend(dev->dev); return ret; } static const char *encoder_names[38] = { "NONE", "INTERNAL_LVDS", "INTERNAL_TMDS1", "INTERNAL_TMDS2", "INTERNAL_DAC1", "INTERNAL_DAC2", "INTERNAL_SDVOA", "INTERNAL_SDVOB", "SI170B", "CH7303", "CH7301", "INTERNAL_DVO1", "EXTERNAL_SDVOA", "EXTERNAL_SDVOB", "TITFP513", "INTERNAL_LVTM1", "VT1623", "HDMI_SI1930", "HDMI_INTERNAL", "INTERNAL_KLDSCP_TMDS1", "INTERNAL_KLDSCP_DVO1", "INTERNAL_KLDSCP_DAC1", "INTERNAL_KLDSCP_DAC2", "SI178", "MVPU_FPGA", "INTERNAL_DDI", "VT1625", "HDMI_SI1932", "DP_AN9801", "DP_DP501", "INTERNAL_UNIPHY", "INTERNAL_KLDSCP_LVTMA", "INTERNAL_UNIPHY1", "INTERNAL_UNIPHY2", "NUTMEG", "TRAVIS", "INTERNAL_VCE", "INTERNAL_UNIPHY3", }; static const char *hpd_names[6] = { "HPD1", "HPD2", "HPD3", "HPD4", "HPD5", "HPD6", }; void amdgpu_print_display_setup(struct drm_device *dev) { struct drm_connector *connector; struct amdgpu_connector *amdgpu_connector; struct drm_encoder *encoder; struct amdgpu_encoder *amdgpu_encoder; uint32_t devices; int i = 0; DRM_INFO("AMDGPU Display Connectors\n"); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { amdgpu_connector = to_amdgpu_connector(connector); DRM_INFO("Connector %d:\n", i); DRM_INFO(" %s\n", connector->name); if (amdgpu_connector->hpd.hpd != AMDGPU_HPD_NONE) DRM_INFO(" %s\n", hpd_names[amdgpu_connector->hpd.hpd]); if (amdgpu_connector->ddc_bus) { DRM_INFO(" DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", amdgpu_connector->ddc_bus->rec.mask_clk_reg, amdgpu_connector->ddc_bus->rec.mask_data_reg, amdgpu_connector->ddc_bus->rec.a_clk_reg, amdgpu_connector->ddc_bus->rec.a_data_reg, amdgpu_connector->ddc_bus->rec.en_clk_reg, amdgpu_connector->ddc_bus->rec.en_data_reg, amdgpu_connector->ddc_bus->rec.y_clk_reg, amdgpu_connector->ddc_bus->rec.y_data_reg); if (amdgpu_connector->router.ddc_valid) DRM_INFO(" DDC Router 0x%x/0x%x\n", amdgpu_connector->router.ddc_mux_control_pin, amdgpu_connector->router.ddc_mux_state); if (amdgpu_connector->router.cd_valid) DRM_INFO(" Clock/Data Router 0x%x/0x%x\n", amdgpu_connector->router.cd_mux_control_pin, amdgpu_connector->router.cd_mux_state); } else { if (connector->connector_type == DRM_MODE_CONNECTOR_VGA || connector->connector_type == DRM_MODE_CONNECTOR_DVII || connector->connector_type == DRM_MODE_CONNECTOR_DVID || connector->connector_type == DRM_MODE_CONNECTOR_DVIA || connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) DRM_INFO(" DDC: no ddc bus - possible BIOS bug - please report to xorg-driver-ati@lists.x.org\n"); } DRM_INFO(" Encoders:\n"); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { amdgpu_encoder = to_amdgpu_encoder(encoder); devices = amdgpu_encoder->devices & amdgpu_connector->devices; if (devices) { if (devices & ATOM_DEVICE_CRT1_SUPPORT) DRM_INFO(" CRT1: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_CRT2_SUPPORT) DRM_INFO(" CRT2: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_LCD1_SUPPORT) DRM_INFO(" LCD1: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_DFP1_SUPPORT) DRM_INFO(" DFP1: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_DFP2_SUPPORT) DRM_INFO(" DFP2: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_DFP3_SUPPORT) DRM_INFO(" DFP3: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_DFP4_SUPPORT) DRM_INFO(" DFP4: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_DFP5_SUPPORT) DRM_INFO(" DFP5: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_DFP6_SUPPORT) DRM_INFO(" DFP6: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_TV1_SUPPORT) DRM_INFO(" TV1: %s\n", encoder_names[amdgpu_encoder->encoder_id]); if (devices & ATOM_DEVICE_CV_SUPPORT) DRM_INFO(" CV: %s\n", encoder_names[amdgpu_encoder->encoder_id]); } } i++; } } /** * amdgpu_ddc_probe * */ bool amdgpu_ddc_probe(struct amdgpu_connector *amdgpu_connector, bool use_aux) { u8 out = 0x0; u8 buf[8]; int ret; struct i2c_msg msgs[] = { { .addr = DDC_ADDR, .flags = 0, .len = 1, .buf = &out, }, { .addr = DDC_ADDR, .flags = I2C_M_RD, .len = 8, .buf = buf, } }; /* on hw with routers, select right port */ if (amdgpu_connector->router.ddc_valid) amdgpu_i2c_router_select_ddc_port(amdgpu_connector); if (use_aux) { ret = i2c_transfer(&amdgpu_connector->ddc_bus->aux.ddc, msgs, 2); } else { ret = i2c_transfer(&amdgpu_connector->ddc_bus->adapter, msgs, 2); } if (ret != 2) /* Couldn't find an accessible DDC on this connector */ return false; /* Probe also for valid EDID header * EDID header starts with: * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00. * Only the first 6 bytes must be valid as * drm_edid_block_valid() can fix the last 2 bytes */ if (drm_edid_header_is_valid(buf) < 6) { /* Couldn't find an accessible EDID on this * connector */ return false; } return true; } static void amdgpu_user_framebuffer_destroy(struct drm_framebuffer *fb) { struct amdgpu_framebuffer *amdgpu_fb = to_amdgpu_framebuffer(fb); if (amdgpu_fb->obj) { drm_gem_object_unreference_unlocked(amdgpu_fb->obj); } drm_framebuffer_cleanup(fb); kfree(amdgpu_fb); } static int amdgpu_user_framebuffer_create_handle(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned int *handle) { struct amdgpu_framebuffer *amdgpu_fb = to_amdgpu_framebuffer(fb); return drm_gem_handle_create(file_priv, amdgpu_fb->obj, handle); } static const struct drm_framebuffer_funcs amdgpu_fb_funcs = { .destroy = amdgpu_user_framebuffer_destroy, .create_handle = amdgpu_user_framebuffer_create_handle, }; int amdgpu_framebuffer_init(struct drm_device *dev, struct amdgpu_framebuffer *rfb, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { int ret; rfb->obj = obj; drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd); ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs); if (ret) { rfb->obj = NULL; return ret; } return 0; } static struct drm_framebuffer * amdgpu_user_framebuffer_create(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *obj; struct amdgpu_framebuffer *amdgpu_fb; int ret; obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); if (obj == NULL) { dev_err(&dev->pdev->dev, "No GEM object associated to handle 0x%08X, " "can't create framebuffer\n", mode_cmd->handles[0]); return ERR_PTR(-ENOENT); } amdgpu_fb = kzalloc(sizeof(*amdgpu_fb), GFP_KERNEL);