• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015 MediaTek Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13 
14 #include <drm/drmP.h>
15 #include <drm/drm_crtc_helper.h>
16 #include <drm/drm_fb_helper.h>
17 #include <drm/drm_gem.h>
18 #include <linux/dma-buf.h>
19 #include <linux/reservation.h>
20 
21 #include "mtk_drm_drv.h"
22 #include "mtk_drm_fb.h"
23 #include "mtk_drm_gem.h"
24 
25 /*
26  * mtk specific framebuffer structure.
27  *
28  * @fb: drm framebuffer object.
29  * @gem_obj: array of gem objects.
30  */
31 struct mtk_drm_fb {
32 	struct drm_framebuffer	base;
33 	/* For now we only support a single plane */
34 	struct drm_gem_object	*gem_obj;
35 };
36 
37 #define to_mtk_fb(x) container_of(x, struct mtk_drm_fb, base)
38 
mtk_fb_get_gem_obj(struct drm_framebuffer * fb)39 struct drm_gem_object *mtk_fb_get_gem_obj(struct drm_framebuffer *fb)
40 {
41 	struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
42 
43 	return mtk_fb->gem_obj;
44 }
45 
mtk_drm_fb_create_handle(struct drm_framebuffer * fb,struct drm_file * file_priv,unsigned int * handle)46 static int mtk_drm_fb_create_handle(struct drm_framebuffer *fb,
47 				    struct drm_file *file_priv,
48 				    unsigned int *handle)
49 {
50 	struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
51 
52 	return drm_gem_handle_create(file_priv, mtk_fb->gem_obj, handle);
53 }
54 
mtk_drm_fb_destroy(struct drm_framebuffer * fb)55 static void mtk_drm_fb_destroy(struct drm_framebuffer *fb)
56 {
57 	struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
58 
59 	drm_framebuffer_cleanup(fb);
60 
61 	drm_gem_object_unreference_unlocked(mtk_fb->gem_obj);
62 
63 	kfree(mtk_fb);
64 }
65 
66 static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = {
67 	.create_handle = mtk_drm_fb_create_handle,
68 	.destroy = mtk_drm_fb_destroy,
69 };
70 
mtk_drm_framebuffer_init(struct drm_device * dev,const struct drm_mode_fb_cmd2 * mode,struct drm_gem_object * obj)71 static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev,
72 					const struct drm_mode_fb_cmd2 *mode,
73 					struct drm_gem_object *obj)
74 {
75 	struct mtk_drm_fb *mtk_fb;
76 	int ret;
77 
78 	if (drm_format_num_planes(mode->pixel_format) != 1)
79 		return ERR_PTR(-EINVAL);
80 
81 	mtk_fb = kzalloc(sizeof(*mtk_fb), GFP_KERNEL);
82 	if (!mtk_fb)
83 		return ERR_PTR(-ENOMEM);
84 
85 	drm_helper_mode_fill_fb_struct(&mtk_fb->base, mode);
86 
87 	mtk_fb->gem_obj = obj;
88 
89 	ret = drm_framebuffer_init(dev, &mtk_fb->base, &mtk_drm_fb_funcs);
90 	if (ret) {
91 		DRM_ERROR("failed to initialize framebuffer\n");
92 		kfree(mtk_fb);
93 		return ERR_PTR(ret);
94 	}
95 
96 	return mtk_fb;
97 }
98 
99 /*
100  * Wait for any exclusive fence in fb's gem object's reservation object.
101  *
102  * Returns -ERESTARTSYS if interrupted, else 0.
103  */
mtk_fb_wait(struct drm_framebuffer * fb)104 int mtk_fb_wait(struct drm_framebuffer *fb)
105 {
106 	struct drm_gem_object *gem;
107 	struct reservation_object *resv;
108 	long ret;
109 
110 	if (!fb)
111 		return 0;
112 
113 	gem = mtk_fb_get_gem_obj(fb);
114 	if (!gem || !gem->dma_buf || !gem->dma_buf->resv)
115 		return 0;
116 
117 	resv = gem->dma_buf->resv;
118 	ret = reservation_object_wait_timeout_rcu(resv, false, true,
119 						  MAX_SCHEDULE_TIMEOUT);
120 	/* MAX_SCHEDULE_TIMEOUT on success, -ERESTARTSYS if interrupted */
121 	if (WARN_ON(ret < 0))
122 		return ret;
123 
124 	return 0;
125 }
126 
mtk_drm_mode_fb_create(struct drm_device * dev,struct drm_file * file,const struct drm_mode_fb_cmd2 * cmd)127 struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
128 					       struct drm_file *file,
129 					       const struct drm_mode_fb_cmd2 *cmd)
130 {
131 	struct mtk_drm_fb *mtk_fb;
132 	struct drm_gem_object *gem;
133 	unsigned int width = cmd->width;
134 	unsigned int height = cmd->height;
135 	unsigned int size, bpp;
136 	int ret;
137 
138 	if (drm_format_num_planes(cmd->pixel_format) != 1)
139 		return ERR_PTR(-EINVAL);
140 
141 	gem = drm_gem_object_lookup(file, cmd->handles[0]);
142 	if (!gem)
143 		return ERR_PTR(-ENOENT);
144 
145 	bpp = drm_format_plane_cpp(cmd->pixel_format, 0);
146 	size = (height - 1) * cmd->pitches[0] + width * bpp;
147 	size += cmd->offsets[0];
148 
149 	if (gem->size < size) {
150 		ret = -EINVAL;
151 		goto unreference;
152 	}
153 
154 	mtk_fb = mtk_drm_framebuffer_init(dev, cmd, gem);
155 	if (IS_ERR(mtk_fb)) {
156 		ret = PTR_ERR(mtk_fb);
157 		goto unreference;
158 	}
159 
160 	return &mtk_fb->base;
161 
162 unreference:
163 	drm_gem_object_unreference_unlocked(gem);
164 	return ERR_PTR(ret);
165 }
166