summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/drm_crtc.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2016-08-25 12:59:50 +1000
committerDave Airlie <airlied@redhat.com>2016-08-25 12:59:50 +1000
commite9c3ddee6a08c5b25cdb06b524320a5a98250513 (patch)
tree41cc2cc030ef965c1d34b336c994a3ac9c00c13e /drivers/gpu/drm/drm_crtc.c
parent51d6120792ab5f46d6f5f7f37b65d05cc1afc019 (diff)
parent7b4d3e297e8a7d3b82e68231ff077e891c370349 (diff)
Merge branch 'drm-next-4.9' of git://people.freedesktop.org/~agd5f/linux into drm-next
First drm-next pull for radeon and amdgpu for 4.9. Highlights: - powerplay support for iceland asics - improved GPU reset (both full asic and per block) - UVD and VCE powergating for CZ and ST - VCE clockgating for CZ and ST - Support for pre-initialized (e.g., zeroed) vram buffers - ttm cleanups - virtual display support - core and radeon/amdgpu support for page_flip_target - lots of bug fixes and clean ups * 'drm-next-4.9' of git://people.freedesktop.org/~agd5f/linux: (171 commits) drm/amdgpu: use memcpy_toio for VCE firmware upload drm/amdgpu: use memcpy_to/fromio for UVD fw upload drm/amd/powerplay: delete useless code in iceland_hwmgr.c. drm/radeon: switch UVD code to use UVD_NO_OP for padding drm/amdgpu: switch UVD code to use UVD_NO_OP for padding drm/radeon: add support for UVD_NO_OP register drm/amdgpu: add support for UVD_NO_OP register drm/amdgpu: fix VCE ib alignment value drm/amdgpu: fix IB alignment for UVD drm/amd/amdgpu: Print ring name in amdgpu_ib_schedule() drm/radeon: remove dead code, si_mc_load_microcode (v2) drm/radeon/cik: remove dead code (v2) drm/amd/powerplay: avoid NULL dereference, cz_hwmgr.c drm/amd/powerplay: avoid NULL pointer dereference drm/amdgpu/gmc8: remove dead code (v2) drm/amdgpu/gmc7: remove dead code (v2) drm/amdgpu: Fix indentation in dce_v8_0_audio_write_sad_regs() drm/amdgpu: Use correct mask in dce_v8_0_afmt_setmode() and fix comment typos. drm/amdgpu: cleanup amdgpu_vm_bo_update params drm/amdgpu: stop adding dummy entry in amdgpu_ttm_placement_init ...
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r--drivers/gpu/drm/drm_crtc.c66
1 files changed, 59 insertions, 7 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 7f2510524f09..7b21281c4b78 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3480,14 +3480,23 @@ out:
int drm_mode_page_flip_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
- struct drm_mode_crtc_page_flip *page_flip = data;
+ struct drm_mode_crtc_page_flip_target *page_flip = data;
struct drm_crtc *crtc;
struct drm_framebuffer *fb = NULL;
struct drm_pending_vblank_event *e = NULL;
+ u32 target_vblank = page_flip->sequence;
int ret = -EINVAL;
- if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
- page_flip->reserved != 0)
+ if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS)
+ return -EINVAL;
+
+ if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET))
+ return -EINVAL;
+
+ /* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags
+ * can be specified
+ */
+ if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET)
return -EINVAL;
if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
@@ -3497,6 +3506,45 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
if (!crtc)
return -ENOENT;
+ if (crtc->funcs->page_flip_target) {
+ u32 current_vblank;
+ int r;
+
+ r = drm_crtc_vblank_get(crtc);
+ if (r)
+ return r;
+
+ current_vblank = drm_crtc_vblank_count(crtc);
+
+ switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {
+ case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:
+ if ((int)(target_vblank - current_vblank) > 1) {
+ DRM_DEBUG("Invalid absolute flip target %u, "
+ "must be <= %u\n", target_vblank,
+ current_vblank + 1);
+ drm_crtc_vblank_put(crtc);
+ return -EINVAL;
+ }
+ break;
+ case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE:
+ if (target_vblank != 0 && target_vblank != 1) {
+ DRM_DEBUG("Invalid relative flip target %u, "
+ "must be 0 or 1\n", target_vblank);
+ drm_crtc_vblank_put(crtc);
+ return -EINVAL;
+ }
+ target_vblank += current_vblank;
+ break;
+ default:
+ target_vblank = current_vblank +
+ !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
+ break;
+ }
+ } else if (crtc->funcs->page_flip == NULL ||
+ (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) {
+ return -EINVAL;
+ }
+
drm_modeset_lock_crtc(crtc, crtc->primary);
if (crtc->primary->fb == NULL) {
/* The framebuffer is currently unbound, presumably
@@ -3507,9 +3555,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
goto out;
}
- if (crtc->funcs->page_flip == NULL)
- goto out;
-
fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
if (!fb) {
ret = -ENOENT;
@@ -3550,7 +3595,12 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
}
crtc->primary->old_fb = crtc->primary->fb;
- ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
+ if (crtc->funcs->page_flip_target)
+ ret = crtc->funcs->page_flip_target(crtc, fb, e,
+ page_flip->flags,
+ target_vblank);
+ else
+ ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
if (ret) {
if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
drm_event_cancel_free(dev, &e->base);
@@ -3563,6 +3613,8 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
}
out:
+ if (ret)
+ drm_crtc_vblank_put(crtc);
if (fb)
drm_framebuffer_unreference(fb);
if (crtc->primary->old_fb)