diff options
Diffstat (limited to 'drivers/gpu/drm/drm_framebuffer.c')
-rw-r--r-- | drivers/gpu/drm/drm_framebuffer.c | 194 |
1 files changed, 88 insertions, 106 deletions
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 398efd67cb93..28a0108a1ab8 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c | |||
@@ -39,13 +39,13 @@ | |||
39 | * Frame buffers rely on the underlying memory manager for allocating backing | 39 | * Frame buffers rely on the underlying memory manager for allocating backing |
40 | * storage. When creating a frame buffer applications pass a memory handle | 40 | * storage. When creating a frame buffer applications pass a memory handle |
41 | * (or a list of memory handles for multi-planar formats) through the | 41 | * (or a list of memory handles for multi-planar formats) through the |
42 | * struct &drm_mode_fb_cmd2 argument. For drivers using GEM as their userspace | 42 | * &struct drm_mode_fb_cmd2 argument. For drivers using GEM as their userspace |
43 | * buffer management interface this would be a GEM handle. Drivers are however | 43 | * buffer management interface this would be a GEM handle. Drivers are however |
44 | * free to use their own backing storage object handles, e.g. vmwgfx directly | 44 | * free to use their own backing storage object handles, e.g. vmwgfx directly |
45 | * exposes special TTM handles to userspace and so expects TTM handles in the | 45 | * exposes special TTM handles to userspace and so expects TTM handles in the |
46 | * create ioctl and not GEM handles. | 46 | * create ioctl and not GEM handles. |
47 | * | 47 | * |
48 | * Framebuffers are tracked with struct &drm_framebuffer. They are published | 48 | * Framebuffers are tracked with &struct drm_framebuffer. They are published |
49 | * using drm_framebuffer_init() - after calling that function userspace can use | 49 | * using drm_framebuffer_init() - after calling that function userspace can use |
50 | * and access the framebuffer object. The helper function | 50 | * and access the framebuffer object. The helper function |
51 | * drm_helper_mode_fill_fb_struct() can be used to pre-fill the required | 51 | * drm_helper_mode_fill_fb_struct() can be used to pre-fill the required |
@@ -55,11 +55,11 @@ | |||
55 | * drivers can grab additional references with drm_framebuffer_reference() and | 55 | * drivers can grab additional references with drm_framebuffer_reference() and |
56 | * drop them again with drm_framebuffer_unreference(). For driver-private | 56 | * drop them again with drm_framebuffer_unreference(). For driver-private |
57 | * framebuffers for which the last reference is never dropped (e.g. for the | 57 | * framebuffers for which the last reference is never dropped (e.g. for the |
58 | * fbdev framebuffer when the struct struct &drm_framebuffer is embedded into | 58 | * fbdev framebuffer when the struct &struct drm_framebuffer is embedded into |
59 | * the fbdev helper struct) drivers can manually clean up a framebuffer at | 59 | * the fbdev helper struct) drivers can manually clean up a framebuffer at |
60 | * module unload time with drm_framebuffer_unregister_private(). But doing this | 60 | * module unload time with drm_framebuffer_unregister_private(). But doing this |
61 | * is not recommended, and it's better to have a normal free-standing struct | 61 | * is not recommended, and it's better to have a normal free-standing &struct |
62 | * &drm_framebuffer. | 62 | * drm_framebuffer. |
63 | */ | 63 | */ |
64 | 64 | ||
65 | int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y, | 65 | int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y, |
@@ -126,111 +126,34 @@ int drm_mode_addfb(struct drm_device *dev, | |||
126 | return 0; | 126 | return 0; |
127 | } | 127 | } |
128 | 128 | ||
129 | static int format_check(const struct drm_mode_fb_cmd2 *r) | ||
130 | { | ||
131 | uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; | ||
132 | char *format_name; | ||
133 | |||
134 | switch (format) { | ||
135 | case DRM_FORMAT_C8: | ||
136 | case DRM_FORMAT_RGB332: | ||
137 | case DRM_FORMAT_BGR233: | ||
138 | case DRM_FORMAT_XRGB4444: | ||
139 | case DRM_FORMAT_XBGR4444: | ||
140 | case DRM_FORMAT_RGBX4444: | ||
141 | case DRM_FORMAT_BGRX4444: | ||
142 | case DRM_FORMAT_ARGB4444: | ||
143 | case DRM_FORMAT_ABGR4444: | ||
144 | case DRM_FORMAT_RGBA4444: | ||
145 | case DRM_FORMAT_BGRA4444: | ||
146 | case DRM_FORMAT_XRGB1555: | ||
147 | case DRM_FORMAT_XBGR1555: | ||
148 | case DRM_FORMAT_RGBX5551: | ||
149 | case DRM_FORMAT_BGRX5551: | ||
150 | case DRM_FORMAT_ARGB1555: | ||
151 | case DRM_FORMAT_ABGR1555: | ||
152 | case DRM_FORMAT_RGBA5551: | ||
153 | case DRM_FORMAT_BGRA5551: | ||
154 | case DRM_FORMAT_RGB565: | ||
155 | case DRM_FORMAT_BGR565: | ||
156 | case DRM_FORMAT_RGB888: | ||
157 | case DRM_FORMAT_BGR888: | ||
158 | case DRM_FORMAT_XRGB8888: | ||
159 | case DRM_FORMAT_XBGR8888: | ||
160 | case DRM_FORMAT_RGBX8888: | ||
161 | case DRM_FORMAT_BGRX8888: | ||
162 | case DRM_FORMAT_ARGB8888: | ||
163 | case DRM_FORMAT_ABGR8888: | ||
164 | case DRM_FORMAT_RGBA8888: | ||
165 | case DRM_FORMAT_BGRA8888: | ||
166 | case DRM_FORMAT_XRGB2101010: | ||
167 | case DRM_FORMAT_XBGR2101010: | ||
168 | case DRM_FORMAT_RGBX1010102: | ||
169 | case DRM_FORMAT_BGRX1010102: | ||
170 | case DRM_FORMAT_ARGB2101010: | ||
171 | case DRM_FORMAT_ABGR2101010: | ||
172 | case DRM_FORMAT_RGBA1010102: | ||
173 | case DRM_FORMAT_BGRA1010102: | ||
174 | case DRM_FORMAT_YUYV: | ||
175 | case DRM_FORMAT_YVYU: | ||
176 | case DRM_FORMAT_UYVY: | ||
177 | case DRM_FORMAT_VYUY: | ||
178 | case DRM_FORMAT_AYUV: | ||
179 | case DRM_FORMAT_NV12: | ||
180 | case DRM_FORMAT_NV21: | ||
181 | case DRM_FORMAT_NV16: | ||
182 | case DRM_FORMAT_NV61: | ||
183 | case DRM_FORMAT_NV24: | ||
184 | case DRM_FORMAT_NV42: | ||
185 | case DRM_FORMAT_YUV410: | ||
186 | case DRM_FORMAT_YVU410: | ||
187 | case DRM_FORMAT_YUV411: | ||
188 | case DRM_FORMAT_YVU411: | ||
189 | case DRM_FORMAT_YUV420: | ||
190 | case DRM_FORMAT_YVU420: | ||
191 | case DRM_FORMAT_YUV422: | ||
192 | case DRM_FORMAT_YVU422: | ||
193 | case DRM_FORMAT_YUV444: | ||
194 | case DRM_FORMAT_YVU444: | ||
195 | return 0; | ||
196 | default: | ||
197 | format_name = drm_get_format_name(r->pixel_format); | ||
198 | DRM_DEBUG_KMS("invalid pixel format %s\n", format_name); | ||
199 | kfree(format_name); | ||
200 | return -EINVAL; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) | 129 | static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) |
205 | { | 130 | { |
206 | int ret, hsub, vsub, num_planes, i; | 131 | const struct drm_format_info *info; |
207 | 132 | int i; | |
208 | ret = format_check(r); | 133 | |
209 | if (ret) { | 134 | info = __drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN); |
210 | char *format_name = drm_get_format_name(r->pixel_format); | 135 | if (!info) { |
211 | DRM_DEBUG_KMS("bad framebuffer format %s\n", format_name); | 136 | struct drm_format_name_buf format_name; |
212 | kfree(format_name); | 137 | DRM_DEBUG_KMS("bad framebuffer format %s\n", |
213 | return ret; | 138 | drm_get_format_name(r->pixel_format, |
139 | &format_name)); | ||
140 | return -EINVAL; | ||
214 | } | 141 | } |
215 | 142 | ||
216 | hsub = drm_format_horz_chroma_subsampling(r->pixel_format); | 143 | if (r->width == 0 || r->width % info->hsub) { |
217 | vsub = drm_format_vert_chroma_subsampling(r->pixel_format); | ||
218 | num_planes = drm_format_num_planes(r->pixel_format); | ||
219 | |||
220 | if (r->width == 0 || r->width % hsub) { | ||
221 | DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); | 144 | DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); |
222 | return -EINVAL; | 145 | return -EINVAL; |
223 | } | 146 | } |
224 | 147 | ||
225 | if (r->height == 0 || r->height % vsub) { | 148 | if (r->height == 0 || r->height % info->vsub) { |
226 | DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); | 149 | DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); |
227 | return -EINVAL; | 150 | return -EINVAL; |
228 | } | 151 | } |
229 | 152 | ||
230 | for (i = 0; i < num_planes; i++) { | 153 | for (i = 0; i < info->num_planes; i++) { |
231 | unsigned int width = r->width / (i != 0 ? hsub : 1); | 154 | unsigned int width = r->width / (i != 0 ? info->hsub : 1); |
232 | unsigned int height = r->height / (i != 0 ? vsub : 1); | 155 | unsigned int height = r->height / (i != 0 ? info->vsub : 1); |
233 | unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); | 156 | unsigned int cpp = info->cpp[i]; |
234 | 157 | ||
235 | if (!r->handles[i]) { | 158 | if (!r->handles[i]) { |
236 | DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); | 159 | DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); |
@@ -254,6 +177,13 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) | |||
254 | return -EINVAL; | 177 | return -EINVAL; |
255 | } | 178 | } |
256 | 179 | ||
180 | if (r->flags & DRM_MODE_FB_MODIFIERS && | ||
181 | r->modifier[i] != r->modifier[0]) { | ||
182 | DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n", | ||
183 | r->modifier[i], i); | ||
184 | return -EINVAL; | ||
185 | } | ||
186 | |||
257 | /* modifier specific checks: */ | 187 | /* modifier specific checks: */ |
258 | switch (r->modifier[i]) { | 188 | switch (r->modifier[i]) { |
259 | case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: | 189 | case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: |
@@ -273,7 +203,7 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) | |||
273 | } | 203 | } |
274 | } | 204 | } |
275 | 205 | ||
276 | for (i = num_planes; i < 4; i++) { | 206 | for (i = info->num_planes; i < 4; i++) { |
277 | if (r->modifier[i]) { | 207 | if (r->modifier[i]) { |
278 | DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i); | 208 | DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i); |
279 | return -EINVAL; | 209 | return -EINVAL; |
@@ -502,8 +432,8 @@ int drm_mode_getfb(struct drm_device *dev, | |||
502 | 432 | ||
503 | r->height = fb->height; | 433 | r->height = fb->height; |
504 | r->width = fb->width; | 434 | r->width = fb->width; |
505 | r->depth = fb->depth; | 435 | r->depth = fb->format->depth; |
506 | r->bpp = fb->bits_per_pixel; | 436 | r->bpp = fb->format->cpp[0] * 8; |
507 | r->pitch = fb->pitches[0]; | 437 | r->pitch = fb->pitches[0]; |
508 | if (fb->funcs->create_handle) { | 438 | if (fb->funcs->create_handle) { |
509 | if (drm_is_current_master(file_priv) || capable(CAP_SYS_ADMIN) || | 439 | if (drm_is_current_master(file_priv) || capable(CAP_SYS_ADMIN) || |
@@ -540,7 +470,7 @@ int drm_mode_getfb(struct drm_device *dev, | |||
540 | * usb display-link, mipi manual update panels or edp panel self refresh modes. | 470 | * usb display-link, mipi manual update panels or edp panel self refresh modes. |
541 | * | 471 | * |
542 | * Modesetting drivers which always update the frontbuffer do not need to | 472 | * Modesetting drivers which always update the frontbuffer do not need to |
543 | * implement the corresponding ->dirty framebuffer callback. | 473 | * implement the corresponding &drm_framebuffer_funcs.dirty callback. |
544 | * | 474 | * |
545 | * Called by the user via ioctl. | 475 | * Called by the user via ioctl. |
546 | * | 476 | * |
@@ -701,8 +631,11 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, | |||
701 | { | 631 | { |
702 | int ret; | 632 | int ret; |
703 | 633 | ||
634 | if (WARN_ON_ONCE(fb->dev != dev || !fb->format)) | ||
635 | return -EINVAL; | ||
636 | |||
704 | INIT_LIST_HEAD(&fb->filp_head); | 637 | INIT_LIST_HEAD(&fb->filp_head); |
705 | fb->dev = dev; | 638 | |
706 | fb->funcs = funcs; | 639 | fb->funcs = funcs; |
707 | 640 | ||
708 | ret = drm_mode_object_get_reg(dev, &fb->base, DRM_MODE_OBJECT_FB, | 641 | ret = drm_mode_object_get_reg(dev, &fb->base, DRM_MODE_OBJECT_FB, |
@@ -751,6 +684,11 @@ EXPORT_SYMBOL(drm_framebuffer_lookup); | |||
751 | * those used for fbdev. Note that the caller must hold a reference of it's own, | 684 | * those used for fbdev. Note that the caller must hold a reference of it's own, |
752 | * i.e. the object may not be destroyed through this call (since it'll lead to a | 685 | * i.e. the object may not be destroyed through this call (since it'll lead to a |
753 | * locking inversion). | 686 | * locking inversion). |
687 | * | ||
688 | * NOTE: This function is deprecated. For driver-private framebuffers it is not | ||
689 | * recommended to embed a framebuffer struct info fbdev struct, instead, a | ||
690 | * framebuffer pointer is preferred and drm_framebuffer_unreference() should be | ||
691 | * called when the framebuffer is to be cleaned up. | ||
754 | */ | 692 | */ |
755 | void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) | 693 | void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) |
756 | { | 694 | { |
@@ -771,10 +709,10 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private); | |||
771 | * @fb: framebuffer to remove | 709 | * @fb: framebuffer to remove |
772 | * | 710 | * |
773 | * Cleanup framebuffer. This function is intended to be used from the drivers | 711 | * Cleanup framebuffer. This function is intended to be used from the drivers |
774 | * ->destroy callback. It can also be used to clean up driver private | 712 | * &drm_framebuffer_funcs.destroy callback. It can also be used to clean up |
775 | * framebuffers embedded into a larger structure. | 713 | * driver private framebuffers embedded into a larger structure. |
776 | * | 714 | * |
777 | * Note that this function does not remove the fb from active usuage - if it is | 715 | * Note that this function does not remove the fb from active usage - if it is |
778 | * still used anywhere, hilarity can ensue since userspace could call getfb on | 716 | * still used anywhere, hilarity can ensue since userspace could call getfb on |
779 | * the id and get back -EINVAL. Obviously no concern at driver unload time. | 717 | * the id and get back -EINVAL. Obviously no concern at driver unload time. |
780 | * | 718 | * |
@@ -855,3 +793,47 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) | |||
855 | drm_framebuffer_unreference(fb); | 793 | drm_framebuffer_unreference(fb); |
856 | } | 794 | } |
857 | EXPORT_SYMBOL(drm_framebuffer_remove); | 795 | EXPORT_SYMBOL(drm_framebuffer_remove); |
796 | |||
797 | /** | ||
798 | * drm_framebuffer_plane_width - width of the plane given the first plane | ||
799 | * @width: width of the first plane | ||
800 | * @fb: the framebuffer | ||
801 | * @plane: plane index | ||
802 | * | ||
803 | * Returns: | ||
804 | * The width of @plane, given that the width of the first plane is @width. | ||
805 | */ | ||
806 | int drm_framebuffer_plane_width(int width, | ||
807 | const struct drm_framebuffer *fb, int plane) | ||
808 | { | ||
809 | if (plane >= fb->format->num_planes) | ||
810 | return 0; | ||
811 | |||
812 | if (plane == 0) | ||
813 | return width; | ||
814 | |||
815 | return width / fb->format->hsub; | ||
816 | } | ||
817 | EXPORT_SYMBOL(drm_framebuffer_plane_width); | ||
818 | |||
819 | /** | ||
820 | * drm_framebuffer_plane_height - height of the plane given the first plane | ||
821 | * @height: height of the first plane | ||
822 | * @fb: the framebuffer | ||
823 | * @plane: plane index | ||
824 | * | ||
825 | * Returns: | ||
826 | * The height of @plane, given that the height of the first plane is @height. | ||
827 | */ | ||
828 | int drm_framebuffer_plane_height(int height, | ||
829 | const struct drm_framebuffer *fb, int plane) | ||
830 | { | ||
831 | if (plane >= fb->format->num_planes) | ||
832 | return 0; | ||
833 | |||
834 | if (plane == 0) | ||
835 | return height; | ||
836 | |||
837 | return height / fb->format->vsub; | ||
838 | } | ||
839 | EXPORT_SYMBOL(drm_framebuffer_plane_height); | ||