• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2012, 2013 Thierry Reding
3  * Copyright © 2013 Erik Faye-Lund
4  * Copyright © 2014 NVIDIA Corporation
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 #include <sys/mman.h>
31 
32 #include <xf86drm.h>
33 
34 #include <tegra_drm.h>
35 
36 #include "private.h"
37 
drm_tegra_bo_free(struct drm_tegra_bo * bo)38 static void drm_tegra_bo_free(struct drm_tegra_bo *bo)
39 {
40 	struct drm_tegra *drm = bo->drm;
41 
42 	if (bo->map)
43 		munmap(bo->map, bo->size);
44 
45 	drmCloseBufferHandle(drm->fd, bo->handle);
46 
47 	free(bo);
48 }
49 
drm_tegra_wrap(struct drm_tegra ** drmp,int fd,bool close)50 static int drm_tegra_wrap(struct drm_tegra **drmp, int fd, bool close)
51 {
52 	struct drm_tegra *drm;
53 
54 	if (fd < 0 || !drmp)
55 		return -EINVAL;
56 
57 	drm = calloc(1, sizeof(*drm));
58 	if (!drm)
59 		return -ENOMEM;
60 
61 	drm->close = close;
62 	drm->fd = fd;
63 
64 	*drmp = drm;
65 
66 	return 0;
67 }
68 
drm_tegra_new(struct drm_tegra ** drmp,int fd)69 drm_public int drm_tegra_new(struct drm_tegra **drmp, int fd)
70 {
71 	bool supported = false;
72 	drmVersionPtr version;
73 
74 	version = drmGetVersion(fd);
75 	if (!version)
76 		return -ENOMEM;
77 
78 	if (!strncmp(version->name, "tegra", version->name_len))
79 		supported = true;
80 
81 	drmFreeVersion(version);
82 
83 	if (!supported)
84 		return -ENOTSUP;
85 
86 	return drm_tegra_wrap(drmp, fd, false);
87 }
88 
drm_tegra_close(struct drm_tegra * drm)89 drm_public void drm_tegra_close(struct drm_tegra *drm)
90 {
91 	if (!drm)
92 		return;
93 
94 	if (drm->close)
95 		close(drm->fd);
96 
97 	free(drm);
98 }
99 
drm_tegra_bo_new(struct drm_tegra_bo ** bop,struct drm_tegra * drm,uint32_t flags,uint32_t size)100 drm_public int drm_tegra_bo_new(struct drm_tegra_bo **bop, struct drm_tegra *drm,
101 		     uint32_t flags, uint32_t size)
102 {
103 	struct drm_tegra_gem_create args;
104 	struct drm_tegra_bo *bo;
105 	int err;
106 
107 	if (!drm || size == 0 || !bop)
108 		return -EINVAL;
109 
110 	bo = calloc(1, sizeof(*bo));
111 	if (!bo)
112 		return -ENOMEM;
113 
114 	atomic_set(&bo->ref, 1);
115 	bo->flags = flags;
116 	bo->size = size;
117 	bo->drm = drm;
118 
119 	memset(&args, 0, sizeof(args));
120 	args.flags = flags;
121 	args.size = size;
122 
123 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_CREATE, &args,
124 				  sizeof(args));
125 	if (err < 0) {
126 		err = -errno;
127 		free(bo);
128 		return err;
129 	}
130 
131 	bo->handle = args.handle;
132 
133 	*bop = bo;
134 
135 	return 0;
136 }
137 
drm_tegra_bo_wrap(struct drm_tegra_bo ** bop,struct drm_tegra * drm,uint32_t handle,uint32_t flags,uint32_t size)138 drm_public int drm_tegra_bo_wrap(struct drm_tegra_bo **bop, struct drm_tegra *drm,
139 		      uint32_t handle, uint32_t flags, uint32_t size)
140 {
141 	struct drm_tegra_bo *bo;
142 
143 	if (!drm || !bop)
144 		return -EINVAL;
145 
146 	bo = calloc(1, sizeof(*bo));
147 	if (!bo)
148 		return -ENOMEM;
149 
150 	atomic_set(&bo->ref, 1);
151 	bo->handle = handle;
152 	bo->flags = flags;
153 	bo->size = size;
154 	bo->drm = drm;
155 
156 	*bop = bo;
157 
158 	return 0;
159 }
160 
drm_tegra_bo_ref(struct drm_tegra_bo * bo)161 drm_public struct drm_tegra_bo *drm_tegra_bo_ref(struct drm_tegra_bo *bo)
162 {
163 	if (bo)
164 		atomic_inc(&bo->ref);
165 
166 	return bo;
167 }
168 
drm_tegra_bo_unref(struct drm_tegra_bo * bo)169 drm_public void drm_tegra_bo_unref(struct drm_tegra_bo *bo)
170 {
171 	if (bo && atomic_dec_and_test(&bo->ref))
172 		drm_tegra_bo_free(bo);
173 }
174 
drm_tegra_bo_get_handle(struct drm_tegra_bo * bo,uint32_t * handle)175 drm_public int drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle)
176 {
177 	if (!bo || !handle)
178 		return -EINVAL;
179 
180 	*handle = bo->handle;
181 
182 	return 0;
183 }
184 
drm_tegra_bo_map(struct drm_tegra_bo * bo,void ** ptr)185 drm_public int drm_tegra_bo_map(struct drm_tegra_bo *bo, void **ptr)
186 {
187 	struct drm_tegra *drm = bo->drm;
188 
189 	if (!bo->map) {
190 		struct drm_tegra_gem_mmap args;
191 		int err;
192 
193 		memset(&args, 0, sizeof(args));
194 		args.handle = bo->handle;
195 
196 		err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_MMAP, &args,
197 					  sizeof(args));
198 		if (err < 0)
199 			return -errno;
200 
201 		bo->offset = args.offset;
202 
203 		bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
204 			       drm->fd, bo->offset);
205 		if (bo->map == MAP_FAILED) {
206 			bo->map = NULL;
207 			return -errno;
208 		}
209 	}
210 
211 	if (ptr)
212 		*ptr = bo->map;
213 
214 	return 0;
215 }
216 
drm_tegra_bo_unmap(struct drm_tegra_bo * bo)217 drm_public int drm_tegra_bo_unmap(struct drm_tegra_bo *bo)
218 {
219 	if (!bo)
220 		return -EINVAL;
221 
222 	if (!bo->map)
223 		return 0;
224 
225 	if (munmap(bo->map, bo->size))
226 		return -errno;
227 
228 	bo->map = NULL;
229 
230 	return 0;
231 }
232 
drm_tegra_bo_get_flags(struct drm_tegra_bo * bo,uint32_t * flags)233 drm_public int drm_tegra_bo_get_flags(struct drm_tegra_bo *bo, uint32_t *flags)
234 {
235 	struct drm_tegra_gem_get_flags args;
236 	struct drm_tegra *drm = bo->drm;
237 	int err;
238 
239 	if (!bo)
240 		return -EINVAL;
241 
242 	memset(&args, 0, sizeof(args));
243 	args.handle = bo->handle;
244 
245 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_FLAGS, &args,
246 				  sizeof(args));
247 	if (err < 0)
248 		return -errno;
249 
250 	if (flags)
251 		*flags = args.flags;
252 
253 	return 0;
254 }
255 
drm_tegra_bo_set_flags(struct drm_tegra_bo * bo,uint32_t flags)256 drm_public int drm_tegra_bo_set_flags(struct drm_tegra_bo *bo, uint32_t flags)
257 {
258 	struct drm_tegra_gem_get_flags args;
259 	struct drm_tegra *drm = bo->drm;
260 	int err;
261 
262 	if (!bo)
263 		return -EINVAL;
264 
265 	memset(&args, 0, sizeof(args));
266 	args.handle = bo->handle;
267 	args.flags = flags;
268 
269 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_FLAGS, &args,
270 				  sizeof(args));
271 	if (err < 0)
272 		return -errno;
273 
274 	return 0;
275 }
276 
drm_tegra_bo_get_tiling(struct drm_tegra_bo * bo,struct drm_tegra_bo_tiling * tiling)277 drm_public int drm_tegra_bo_get_tiling(struct drm_tegra_bo *bo,
278 			    struct drm_tegra_bo_tiling *tiling)
279 {
280 	struct drm_tegra_gem_get_tiling args;
281 	struct drm_tegra *drm = bo->drm;
282 	int err;
283 
284 	if (!bo)
285 		return -EINVAL;
286 
287 	memset(&args, 0, sizeof(args));
288 	args.handle = bo->handle;
289 
290 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_TILING, &args,
291 				  sizeof(args));
292 	if (err < 0)
293 		return -errno;
294 
295 	if (tiling) {
296 		tiling->mode = args.mode;
297 		tiling->value = args.value;
298 	}
299 
300 	return 0;
301 }
302 
drm_tegra_bo_set_tiling(struct drm_tegra_bo * bo,const struct drm_tegra_bo_tiling * tiling)303 drm_public int drm_tegra_bo_set_tiling(struct drm_tegra_bo *bo,
304 			    const struct drm_tegra_bo_tiling *tiling)
305 {
306 	struct drm_tegra_gem_set_tiling args;
307 	struct drm_tegra *drm = bo->drm;
308 	int err;
309 
310 	if (!bo)
311 		return -EINVAL;
312 
313 	memset(&args, 0, sizeof(args));
314 	args.handle = bo->handle;
315 	args.mode = tiling->mode;
316 	args.value = tiling->value;
317 
318 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_TILING, &args,
319 				  sizeof(args));
320 	if (err < 0)
321 		return -errno;
322 
323 	return 0;
324 }
325