From: Rob Clark <rob@xxxxxx> --- drivers/gpu/drm/drm_crtc.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_drv.c | 1 + include/drm/drm.h | 2 ++ include/drm/drm_crtc.h | 2 ++ include/drm/drm_mode.h | 38 ++++++++++++++++++++++ 5 files changed, 118 insertions(+) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 7337fd8..baca5ba 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4219,6 +4219,81 @@ out_unlock: return ret; } +int drm_mode_atomic_page_flip_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_crtc_atomic_page_flip *page_flip = data; + struct drm_mode_obj_set_property __user *props = + (struct drm_mode_obj_set_property __user *) + (unsigned long)page_flip->props_ptr; + struct drm_pending_vblank_event *e = NULL; + struct drm_mode_object *obj; + void *state; + int i, ret; + + if (page_flip->flags & ~DRM_MODE_ATOMIC_PAGE_FLIP_FLAGS || + page_flip->reserved != 0) + return -EINVAL; + + if (!drm_core_check_feature(dev, DRIVER_MODESET) || + !dev_supports_atomic(dev)) + return -EINVAL; + + mutex_lock(&dev->mode_config.mutex); + + obj = drm_mode_object_find(dev, page_flip->crtc_id, + DRM_MODE_OBJECT_CRTC); + if (!obj) { + DRM_DEBUG_KMS("Unknown CRTC ID %d\n", page_flip->crtc_id); + ret = -ENOENT; + goto out_unlock; + } + + state = dev->driver->atomic_begin(dev, obj_to_crtc(obj)); + if (IS_ERR(state)) { + ret = PTR_ERR(state); + goto out_unlock; + } + + if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { + e = create_vblank_event(dev, file_priv, page_flip->user_data); + if (!e) { + ret = -ENOMEM; + goto out; + } + } + + for (i = 0; i < page_flip->count_props; i++) { + struct drm_mode_obj_set_property prop; + if (copy_from_user(&prop, &props[i], sizeof(prop))) { + ret = -EFAULT; + goto out; + } + + ret = drm_mode_set_obj_prop_id(dev, state, + prop.obj_id, prop.obj_type, + prop.prop_id, prop.value); + if (ret) + goto out; + } + + ret = dev->driver->atomic_check(dev, state); + if (ret) + goto out; + + if (!(page_flip->flags & DRM_MODE_TEST_ONLY)) + ret = dev->driver->atomic_commit(dev, state, e); + + if (ret && e) + destroy_vblank_event(dev, file_priv, e); + +out: + dev->driver->atomic_end(dev, state); +out_unlock: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + void drm_mode_config_reset(struct drm_device *dev) { struct drm_crtc *crtc; diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 52717ef2..b7bb78a 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -166,6 +166,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC_PAGE_FLIP, drm_mode_atomic_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/include/drm/drm.h b/include/drm/drm.h index e51035a..0908741 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h @@ -732,6 +732,8 @@ struct drm_prime_handle { #define DRM_IOCTL_MODE_ADDFB2 DRM_IOWR(0xB8, struct drm_mode_fb_cmd2) #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties) #define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property) +/* placeholder for DRM_IOCTL_ATOMIC_MODE_SET */ +#define DRM_IOCTL_MODE_ATOMIC_PAGE_FLIP DRM_IOWR(0xBC, struct drm_mode_crtc_atomic_page_flip) /** * Device specific ioctls should only be in their respective headers diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index f445135..47c043f 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1129,6 +1129,8 @@ extern bool drm_detect_hdmi_monitor(struct edid *edid); extern bool drm_detect_monitor_audio(struct edid *edid); extern int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_atomic_page_flip_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh, bool reduced, bool interlaced, bool margins); diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h index f9232e4..7da6741 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h @@ -411,7 +411,10 @@ struct drm_mode_crtc_lut { }; #define DRM_MODE_PAGE_FLIP_EVENT 0x01 +#define DRM_MODE_TEST_ONLY 0x02 #define DRM_MODE_PAGE_FLIP_FLAGS DRM_MODE_PAGE_FLIP_EVENT +#define DRM_MODE_ATOMIC_PAGE_FLIP_FLAGS \ + (DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_TEST_ONLY) /* * Request a page flip on the specified crtc. @@ -443,6 +446,41 @@ struct drm_mode_crtc_page_flip { __u64 user_data; }; +/* + * Request a page flip on the crtc specified by 'crtc_id' plus zero or + * more planes attached to this crtc. + * + * This ioctl will ask KMS to schedule a page flip for the specified + * crtc. Once any pending rendering targeting the specified fb(s) (as + * of ioctl time) has completed, the crtc and zero or more planes will + * be reprogrammed to display the new fb(s) after the next vertical + * refresh. The ioctl returns immediately, but subsequent rendering + * to the current fb will block in the execbuffer ioctl until the page + * flip happens. If a page flip is already pending as the ioctl is + * called, EBUSY will be returned. + * + * The ioctl supports the following flags: + * + DRM_MODE_PAGE_FLIP_EVENT, which will request that drm sends back + * a vblank event (see drm.h: struct drm_event_vblank) when the page + * flip is done. The user_data field passed in with this ioctl will + * be returned as the user_data field in the vblank event struct. + * + DRM_MODE_TEST_ONLY, don't actually apply the changes (or generate + * a vblank event) but just test the configuration to see if it is + * possible. + * + * The reserved field must be zero until we figure out something clever + * to use it for. + */ + +struct drm_mode_crtc_atomic_page_flip { + uint32_t crtc_id; + uint32_t flags; + uint64_t user_data; + uint32_t reserved; + uint32_t count_props; + uint64_t props_ptr; /* ptr to array of drm_mode_obj_set_property */ +}; + /* create a dumb scanout buffer */ struct drm_mode_create_dumb { uint32_t height; -- 1.7.9.5 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel