diff options
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 69 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_drv.c | 1 | ||||
-rw-r--r-- | include/drm/drm.h | 1 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 16 | ||||
-rw-r--r-- | include/drm/drm_mode.h | 33 |
5 files changed, 120 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5cae0b3eee9b..32756e67dd56 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -2478,3 +2478,72 @@ out: | |||
2478 | mutex_unlock(&dev->mode_config.mutex); | 2478 | mutex_unlock(&dev->mode_config.mutex); |
2479 | return ret; | 2479 | return ret; |
2480 | } | 2480 | } |
2481 | |||
2482 | int drm_mode_page_flip_ioctl(struct drm_device *dev, | ||
2483 | void *data, struct drm_file *file_priv) | ||
2484 | { | ||
2485 | struct drm_mode_crtc_page_flip *page_flip = data; | ||
2486 | struct drm_mode_object *obj; | ||
2487 | struct drm_crtc *crtc; | ||
2488 | struct drm_framebuffer *fb; | ||
2489 | struct drm_pending_vblank_event *e = NULL; | ||
2490 | unsigned long flags; | ||
2491 | int ret = -EINVAL; | ||
2492 | |||
2493 | if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || | ||
2494 | page_flip->reserved != 0) | ||
2495 | return -EINVAL; | ||
2496 | |||
2497 | mutex_lock(&dev->mode_config.mutex); | ||
2498 | obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC); | ||
2499 | if (!obj) | ||
2500 | goto out; | ||
2501 | crtc = obj_to_crtc(obj); | ||
2502 | |||
2503 | if (crtc->funcs->page_flip == NULL) | ||
2504 | goto out; | ||
2505 | |||
2506 | obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB); | ||
2507 | if (!obj) | ||
2508 | goto out; | ||
2509 | fb = obj_to_fb(obj); | ||
2510 | |||
2511 | if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { | ||
2512 | ret = -ENOMEM; | ||
2513 | spin_lock_irqsave(&dev->event_lock, flags); | ||
2514 | if (file_priv->event_space < sizeof e->event) { | ||
2515 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
2516 | goto out; | ||
2517 | } | ||
2518 | file_priv->event_space -= sizeof e->event; | ||
2519 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
2520 | |||
2521 | e = kzalloc(sizeof *e, GFP_KERNEL); | ||
2522 | if (e == NULL) { | ||
2523 | spin_lock_irqsave(&dev->event_lock, flags); | ||
2524 | file_priv->event_space += sizeof e->event; | ||
2525 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
2526 | goto out; | ||
2527 | } | ||
2528 | |||
2529 | e->event.base.type = DRM_EVENT_VBLANK; | ||
2530 | e->event.base.length = sizeof e->event; | ||
2531 | e->event.user_data = page_flip->user_data; | ||
2532 | e->base.event = &e->event.base; | ||
2533 | e->base.file_priv = file_priv; | ||
2534 | e->base.destroy = | ||
2535 | (void (*) (struct drm_pending_event *)) kfree; | ||
2536 | } | ||
2537 | |||
2538 | ret = crtc->funcs->page_flip(crtc, fb, e); | ||
2539 | if (ret) { | ||
2540 | spin_lock_irqsave(&dev->event_lock, flags); | ||
2541 | file_priv->event_space += sizeof e->event; | ||
2542 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
2543 | kfree(e); | ||
2544 | } | ||
2545 | |||
2546 | out: | ||
2547 | mutex_unlock(&dev->mode_config.mutex); | ||
2548 | return ret; | ||
2549 | } | ||
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 5bd3f9461e2d..bfaf59b02bda 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c | |||
@@ -145,6 +145,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { | |||
145 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW), | 145 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW), |
146 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW), | 146 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW), |
147 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW), | 147 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW), |
148 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), | ||
148 | }; | 149 | }; |
149 | 150 | ||
150 | #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) | 151 | #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) |
diff --git a/include/drm/drm.h b/include/drm/drm.h index fa6d9155873d..3919a4f792ae 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h | |||
@@ -687,6 +687,7 @@ struct drm_gem_open { | |||
687 | #define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xAD, struct drm_mode_fb_cmd) | 687 | #define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xAD, struct drm_mode_fb_cmd) |
688 | #define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd) | 688 | #define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd) |
689 | #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, unsigned int) | 689 | #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, unsigned int) |
690 | #define DRM_IOCTL_MODE_PAGE_FLIP DRM_IOWR(0xB0, struct drm_mode_crtc_page_flip) | ||
690 | 691 | ||
691 | /** | 692 | /** |
692 | * Device specific ioctls should only be in their respective headers | 693 | * 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 b69347b8904f..4cc8a32dc4cf 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -290,6 +290,7 @@ struct drm_property { | |||
290 | struct drm_crtc; | 290 | struct drm_crtc; |
291 | struct drm_connector; | 291 | struct drm_connector; |
292 | struct drm_encoder; | 292 | struct drm_encoder; |
293 | struct drm_pending_vblank_event; | ||
293 | 294 | ||
294 | /** | 295 | /** |
295 | * drm_crtc_funcs - control CRTCs for a given device | 296 | * drm_crtc_funcs - control CRTCs for a given device |
@@ -333,6 +334,19 @@ struct drm_crtc_funcs { | |||
333 | void (*destroy)(struct drm_crtc *crtc); | 334 | void (*destroy)(struct drm_crtc *crtc); |
334 | 335 | ||
335 | int (*set_config)(struct drm_mode_set *set); | 336 | int (*set_config)(struct drm_mode_set *set); |
337 | |||
338 | /* | ||
339 | * Flip to the given framebuffer. This implements the page | ||
340 | * flip ioctl descibed in drm_mode.h, specifically, the | ||
341 | * implementation must return immediately and block all | ||
342 | * rendering to the current fb until the flip has completed. | ||
343 | * If userspace set the event flag in the ioctl, the event | ||
344 | * argument will point to an event to send back when the flip | ||
345 | * completes, otherwise it will be NULL. | ||
346 | */ | ||
347 | int (*page_flip)(struct drm_crtc *crtc, | ||
348 | struct drm_framebuffer *fb, | ||
349 | struct drm_pending_vblank_event *event); | ||
336 | }; | 350 | }; |
337 | 351 | ||
338 | /** | 352 | /** |
@@ -756,6 +770,8 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev, | |||
756 | extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, | 770 | extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, |
757 | void *data, struct drm_file *file_priv); | 771 | void *data, struct drm_file *file_priv); |
758 | extern bool drm_detect_hdmi_monitor(struct edid *edid); | 772 | extern bool drm_detect_hdmi_monitor(struct edid *edid); |
773 | extern int drm_mode_page_flip_ioctl(struct drm_device *dev, | ||
774 | void *data, struct drm_file *file_priv); | ||
759 | extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, | 775 | extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, |
760 | int hdisplay, int vdisplay, int vrefresh, | 776 | int hdisplay, int vdisplay, int vrefresh, |
761 | bool reduced, bool interlaced, bool margins); | 777 | bool reduced, bool interlaced, bool margins); |
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h index 1f908416aedb..68ddc6175ae7 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h | |||
@@ -268,4 +268,37 @@ struct drm_mode_crtc_lut { | |||
268 | __u64 blue; | 268 | __u64 blue; |
269 | }; | 269 | }; |
270 | 270 | ||
271 | #define DRM_MODE_PAGE_FLIP_EVENT 0x01 | ||
272 | #define DRM_MODE_PAGE_FLIP_FLAGS DRM_MODE_PAGE_FLIP_EVENT | ||
273 | |||
274 | /* | ||
275 | * Request a page flip on the specified crtc. | ||
276 | * | ||
277 | * This ioctl will ask KMS to schedule a page flip for the specified | ||
278 | * crtc. Once any pending rendering targeting the specified fb (as of | ||
279 | * ioctl time) has completed, the crtc will be reprogrammed to display | ||
280 | * that fb after the next vertical refresh. The ioctl returns | ||
281 | * immediately, but subsequent rendering to the current fb will block | ||
282 | * in the execbuffer ioctl until the page flip happens. If a page | ||
283 | * flip is already pending as the ioctl is called, EBUSY will be | ||
284 | * returned. | ||
285 | * | ||
286 | * The ioctl supports one flag, DRM_MODE_PAGE_FLIP_EVENT, which will | ||
287 | * request that drm sends back a vblank event (see drm.h: struct | ||
288 | * drm_event_vblank) when the page flip is done. The user_data field | ||
289 | * passed in with this ioctl will be returned as the user_data field | ||
290 | * in the vblank event struct. | ||
291 | * | ||
292 | * The reserved field must be zero until we figure out something | ||
293 | * clever to use it for. | ||
294 | */ | ||
295 | |||
296 | struct drm_mode_crtc_page_flip { | ||
297 | __u32 crtc_id; | ||
298 | __u32 fb_id; | ||
299 | __u32 flags; | ||
300 | __u32 reserved; | ||
301 | __u64 user_data; | ||
302 | }; | ||
303 | |||
271 | #endif | 304 | #endif |