diff options
Diffstat (limited to 'drivers/gpu/drm/drm_crtc.c')
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 139 |
1 files changed, 107 insertions, 32 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 271ffa4fdb47..ef1b22144d37 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -293,6 +293,8 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, | |||
293 | { | 293 | { |
294 | int ret; | 294 | int ret; |
295 | 295 | ||
296 | kref_init(&fb->refcount); | ||
297 | |||
296 | ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); | 298 | ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); |
297 | if (ret) | 299 | if (ret) |
298 | return ret; | 300 | return ret; |
@@ -306,6 +308,38 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, | |||
306 | } | 308 | } |
307 | EXPORT_SYMBOL(drm_framebuffer_init); | 309 | EXPORT_SYMBOL(drm_framebuffer_init); |
308 | 310 | ||
311 | static void drm_framebuffer_free(struct kref *kref) | ||
312 | { | ||
313 | struct drm_framebuffer *fb = | ||
314 | container_of(kref, struct drm_framebuffer, refcount); | ||
315 | fb->funcs->destroy(fb); | ||
316 | } | ||
317 | |||
318 | /** | ||
319 | * drm_framebuffer_unreference - unref a framebuffer | ||
320 | * | ||
321 | * LOCKING: | ||
322 | * Caller must hold mode config lock. | ||
323 | */ | ||
324 | void drm_framebuffer_unreference(struct drm_framebuffer *fb) | ||
325 | { | ||
326 | struct drm_device *dev = fb->dev; | ||
327 | DRM_DEBUG("FB ID: %d\n", fb->base.id); | ||
328 | WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); | ||
329 | kref_put(&fb->refcount, drm_framebuffer_free); | ||
330 | } | ||
331 | EXPORT_SYMBOL(drm_framebuffer_unreference); | ||
332 | |||
333 | /** | ||
334 | * drm_framebuffer_reference - incr the fb refcnt | ||
335 | */ | ||
336 | void drm_framebuffer_reference(struct drm_framebuffer *fb) | ||
337 | { | ||
338 | DRM_DEBUG("FB ID: %d\n", fb->base.id); | ||
339 | kref_get(&fb->refcount); | ||
340 | } | ||
341 | EXPORT_SYMBOL(drm_framebuffer_reference); | ||
342 | |||
309 | /** | 343 | /** |
310 | * drm_framebuffer_cleanup - remove a framebuffer object | 344 | * drm_framebuffer_cleanup - remove a framebuffer object |
311 | * @fb: framebuffer to remove | 345 | * @fb: framebuffer to remove |
@@ -319,6 +353,32 @@ EXPORT_SYMBOL(drm_framebuffer_init); | |||
319 | void drm_framebuffer_cleanup(struct drm_framebuffer *fb) | 353 | void drm_framebuffer_cleanup(struct drm_framebuffer *fb) |
320 | { | 354 | { |
321 | struct drm_device *dev = fb->dev; | 355 | struct drm_device *dev = fb->dev; |
356 | /* | ||
357 | * This could be moved to drm_framebuffer_remove(), but for | ||
358 | * debugging is nice to keep around the list of fb's that are | ||
359 | * no longer associated w/ a drm_file but are not unreferenced | ||
360 | * yet. (i915 and omapdrm have debugfs files which will show | ||
361 | * this.) | ||
362 | */ | ||
363 | drm_mode_object_put(dev, &fb->base); | ||
364 | list_del(&fb->head); | ||
365 | dev->mode_config.num_fb--; | ||
366 | } | ||
367 | EXPORT_SYMBOL(drm_framebuffer_cleanup); | ||
368 | |||
369 | /** | ||
370 | * drm_framebuffer_remove - remove and unreference a framebuffer object | ||
371 | * @fb: framebuffer to remove | ||
372 | * | ||
373 | * LOCKING: | ||
374 | * Caller must hold mode config lock. | ||
375 | * | ||
376 | * Scans all the CRTCs and planes in @dev's mode_config. If they're | ||
377 | * using @fb, removes it, setting it to NULL. | ||
378 | */ | ||
379 | void drm_framebuffer_remove(struct drm_framebuffer *fb) | ||
380 | { | ||
381 | struct drm_device *dev = fb->dev; | ||
322 | struct drm_crtc *crtc; | 382 | struct drm_crtc *crtc; |
323 | struct drm_plane *plane; | 383 | struct drm_plane *plane; |
324 | struct drm_mode_set set; | 384 | struct drm_mode_set set; |
@@ -349,11 +409,11 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) | |||
349 | } | 409 | } |
350 | } | 410 | } |
351 | 411 | ||
352 | drm_mode_object_put(dev, &fb->base); | 412 | list_del(&fb->filp_head); |
353 | list_del(&fb->head); | 413 | |
354 | dev->mode_config.num_fb--; | 414 | drm_framebuffer_unreference(fb); |
355 | } | 415 | } |
356 | EXPORT_SYMBOL(drm_framebuffer_cleanup); | 416 | EXPORT_SYMBOL(drm_framebuffer_remove); |
357 | 417 | ||
358 | /** | 418 | /** |
359 | * drm_crtc_init - Initialise a new CRTC object | 419 | * drm_crtc_init - Initialise a new CRTC object |
@@ -376,6 +436,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, | |||
376 | 436 | ||
377 | crtc->dev = dev; | 437 | crtc->dev = dev; |
378 | crtc->funcs = funcs; | 438 | crtc->funcs = funcs; |
439 | crtc->invert_dimensions = false; | ||
379 | 440 | ||
380 | mutex_lock(&dev->mode_config.mutex); | 441 | mutex_lock(&dev->mode_config.mutex); |
381 | 442 | ||
@@ -1030,11 +1091,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) | |||
1030 | } | 1091 | } |
1031 | 1092 | ||
1032 | list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { | 1093 | list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { |
1033 | fb->funcs->destroy(fb); | 1094 | drm_framebuffer_remove(fb); |
1034 | } | ||
1035 | |||
1036 | list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { | ||
1037 | crtc->funcs->destroy(crtc); | ||
1038 | } | 1095 | } |
1039 | 1096 | ||
1040 | list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, | 1097 | list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, |
@@ -1042,6 +1099,10 @@ void drm_mode_config_cleanup(struct drm_device *dev) | |||
1042 | plane->funcs->destroy(plane); | 1099 | plane->funcs->destroy(plane); |
1043 | } | 1100 | } |
1044 | 1101 | ||
1102 | list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { | ||
1103 | crtc->funcs->destroy(crtc); | ||
1104 | } | ||
1105 | |||
1045 | idr_remove_all(&dev->mode_config.crtc_idr); | 1106 | idr_remove_all(&dev->mode_config.crtc_idr); |
1046 | idr_destroy(&dev->mode_config.crtc_idr); | 1107 | idr_destroy(&dev->mode_config.crtc_idr); |
1047 | } | 1108 | } |
@@ -1851,6 +1912,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, | |||
1851 | DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); | 1912 | DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); |
1852 | 1913 | ||
1853 | if (crtc_req->mode_valid) { | 1914 | if (crtc_req->mode_valid) { |
1915 | int hdisplay, vdisplay; | ||
1854 | /* If we have a mode we need a framebuffer. */ | 1916 | /* If we have a mode we need a framebuffer. */ |
1855 | /* If we pass -1, set the mode with the currently bound fb */ | 1917 | /* If we pass -1, set the mode with the currently bound fb */ |
1856 | if (crtc_req->fb_id == -1) { | 1918 | if (crtc_req->fb_id == -1) { |
@@ -1886,14 +1948,20 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, | |||
1886 | 1948 | ||
1887 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); | 1949 | drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); |
1888 | 1950 | ||
1889 | if (mode->hdisplay > fb->width || | 1951 | hdisplay = mode->hdisplay; |
1890 | mode->vdisplay > fb->height || | 1952 | vdisplay = mode->vdisplay; |
1891 | crtc_req->x > fb->width - mode->hdisplay || | 1953 | |
1892 | crtc_req->y > fb->height - mode->vdisplay) { | 1954 | if (crtc->invert_dimensions) |
1893 | DRM_DEBUG_KMS("Invalid CRTC viewport %ux%u+%u+%u for fb size %ux%u.\n", | 1955 | swap(hdisplay, vdisplay); |
1894 | mode->hdisplay, mode->vdisplay, | 1956 | |
1895 | crtc_req->x, crtc_req->y, | 1957 | if (hdisplay > fb->width || |
1896 | fb->width, fb->height); | 1958 | vdisplay > fb->height || |
1959 | crtc_req->x > fb->width - hdisplay || | ||
1960 | crtc_req->y > fb->height - vdisplay) { | ||
1961 | DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", | ||
1962 | fb->width, fb->height, | ||
1963 | hdisplay, vdisplay, crtc_req->x, crtc_req->y, | ||
1964 | crtc->invert_dimensions ? " (inverted)" : ""); | ||
1897 | ret = -ENOSPC; | 1965 | ret = -ENOSPC; |
1898 | goto out; | 1966 | goto out; |
1899 | } | 1967 | } |
@@ -2168,6 +2236,8 @@ static int format_check(const struct drm_mode_fb_cmd2 *r) | |||
2168 | case DRM_FORMAT_NV21: | 2236 | case DRM_FORMAT_NV21: |
2169 | case DRM_FORMAT_NV16: | 2237 | case DRM_FORMAT_NV16: |
2170 | case DRM_FORMAT_NV61: | 2238 | case DRM_FORMAT_NV61: |
2239 | case DRM_FORMAT_NV24: | ||
2240 | case DRM_FORMAT_NV42: | ||
2171 | case DRM_FORMAT_YUV410: | 2241 | case DRM_FORMAT_YUV410: |
2172 | case DRM_FORMAT_YVU410: | 2242 | case DRM_FORMAT_YVU410: |
2173 | case DRM_FORMAT_YUV411: | 2243 | case DRM_FORMAT_YUV411: |
@@ -2334,11 +2404,7 @@ int drm_mode_rmfb(struct drm_device *dev, | |||
2334 | goto out; | 2404 | goto out; |
2335 | } | 2405 | } |
2336 | 2406 | ||
2337 | /* TODO release all crtc connected to the framebuffer */ | 2407 | drm_framebuffer_remove(fb); |
2338 | /* TODO unhock the destructor from the buffer object */ | ||
2339 | |||
2340 | list_del(&fb->filp_head); | ||
2341 | fb->funcs->destroy(fb); | ||
2342 | 2408 | ||
2343 | out: | 2409 | out: |
2344 | mutex_unlock(&dev->mode_config.mutex); | 2410 | mutex_unlock(&dev->mode_config.mutex); |
@@ -2488,8 +2554,7 @@ void drm_fb_release(struct drm_file *priv) | |||
2488 | 2554 | ||
2489 | mutex_lock(&dev->mode_config.mutex); | 2555 | mutex_lock(&dev->mode_config.mutex); |
2490 | list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { | 2556 | list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { |
2491 | list_del(&fb->filp_head); | 2557 | drm_framebuffer_remove(fb); |
2492 | fb->funcs->destroy(fb); | ||
2493 | } | 2558 | } |
2494 | mutex_unlock(&dev->mode_config.mutex); | 2559 | mutex_unlock(&dev->mode_config.mutex); |
2495 | } | 2560 | } |
@@ -3488,6 +3553,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
3488 | struct drm_framebuffer *fb; | 3553 | struct drm_framebuffer *fb; |
3489 | struct drm_pending_vblank_event *e = NULL; | 3554 | struct drm_pending_vblank_event *e = NULL; |
3490 | unsigned long flags; | 3555 | unsigned long flags; |
3556 | int hdisplay, vdisplay; | ||
3491 | int ret = -EINVAL; | 3557 | int ret = -EINVAL; |
3492 | 3558 | ||
3493 | if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || | 3559 | if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || |
@@ -3517,14 +3583,19 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, | |||
3517 | goto out; | 3583 | goto out; |
3518 | fb = obj_to_fb(obj); | 3584 | fb = obj_to_fb(obj); |
3519 | 3585 | ||
3520 | if (crtc->mode.hdisplay > fb->width || | 3586 | hdisplay = crtc->mode.hdisplay; |
3521 | crtc->mode.vdisplay > fb->height || | 3587 | vdisplay = crtc->mode.vdisplay; |
3522 | crtc->x > fb->width - crtc->mode.hdisplay || | 3588 | |
3523 | crtc->y > fb->height - crtc->mode.vdisplay) { | 3589 | if (crtc->invert_dimensions) |
3524 | DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d.\n", | 3590 | swap(hdisplay, vdisplay); |
3525 | fb->width, fb->height, | 3591 | |
3526 | crtc->mode.hdisplay, crtc->mode.vdisplay, | 3592 | if (hdisplay > fb->width || |
3527 | crtc->x, crtc->y); | 3593 | vdisplay > fb->height || |
3594 | crtc->x > fb->width - hdisplay || | ||
3595 | crtc->y > fb->height - vdisplay) { | ||
3596 | DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", | ||
3597 | fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y, | ||
3598 | crtc->invert_dimensions ? " (inverted)" : ""); | ||
3528 | ret = -ENOSPC; | 3599 | ret = -ENOSPC; |
3529 | goto out; | 3600 | goto out; |
3530 | } | 3601 | } |
@@ -3717,6 +3788,8 @@ int drm_format_num_planes(uint32_t format) | |||
3717 | case DRM_FORMAT_NV21: | 3788 | case DRM_FORMAT_NV21: |
3718 | case DRM_FORMAT_NV16: | 3789 | case DRM_FORMAT_NV16: |
3719 | case DRM_FORMAT_NV61: | 3790 | case DRM_FORMAT_NV61: |
3791 | case DRM_FORMAT_NV24: | ||
3792 | case DRM_FORMAT_NV42: | ||
3720 | return 2; | 3793 | return 2; |
3721 | default: | 3794 | default: |
3722 | return 1; | 3795 | return 1; |
@@ -3750,6 +3823,8 @@ int drm_format_plane_cpp(uint32_t format, int plane) | |||
3750 | case DRM_FORMAT_NV21: | 3823 | case DRM_FORMAT_NV21: |
3751 | case DRM_FORMAT_NV16: | 3824 | case DRM_FORMAT_NV16: |
3752 | case DRM_FORMAT_NV61: | 3825 | case DRM_FORMAT_NV61: |
3826 | case DRM_FORMAT_NV24: | ||
3827 | case DRM_FORMAT_NV42: | ||
3753 | return plane ? 2 : 1; | 3828 | return plane ? 2 : 1; |
3754 | case DRM_FORMAT_YUV410: | 3829 | case DRM_FORMAT_YUV410: |
3755 | case DRM_FORMAT_YVU410: | 3830 | case DRM_FORMAT_YVU410: |