omap: fix compiler warning
[gstreamer-omap:libdrm.git] / omap / omap_drm.c
1 /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
2
3 /*
4  * Copyright (C) 2011 Texas Instruments, Inc
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 (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  *
25  * Authors:
26  *    Rob Clark <rob@ti.com>
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <stdlib.h>
34 #include <linux/stddef.h>
35 #include <errno.h>
36 #include <sys/mman.h>
37
38 #include <xf86drm.h>
39
40 #include "omap_drm.h"
41 #include "omap_drmif.h"
42
43 #define __round_mask(x, y) ((__typeof__(x))((y)-1))
44 #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
45 #define PAGE_SIZE 4096
46
47 struct omap_device {
48         int fd;
49 };
50
51 /* a GEM buffer object allocated from the DRM device */
52 struct omap_bo {
53         struct omap_device      *dev;
54         void            *map;           /* userspace mmap'ing (if there is one) */
55         uint32_t        size;
56         uint32_t        handle;
57         uint32_t        name;           /* flink global handle (DRI2 name) */
58         uint64_t        offset;         /* offset to mmap() */
59 };
60
61 struct omap_device * omap_device_new(int fd)
62 {
63         struct omap_device *dev = calloc(sizeof(*dev), 1);
64         if (!dev)
65                 return NULL;
66         dev->fd = fd;
67         return dev;
68 }
69
70 void omap_device_del(struct omap_device *dev)
71 {
72         free(dev);
73 }
74
75 int omap_get_param(struct omap_device *dev, uint64_t param, uint64_t *value)
76 {
77         struct drm_omap_param req = {
78                         .param = param,
79         };
80         int ret;
81
82         ret = drmCommandWriteRead(dev->fd, DRM_OMAP_GET_PARAM, &req, sizeof(req));
83         if (ret) {
84                 return ret;
85         }
86
87         *value = req.value;
88
89         return 0;
90 }
91
92 int omap_set_param(struct omap_device *dev, uint64_t param, uint64_t value)
93 {
94         struct drm_omap_param req = {
95                         .param = param,
96                         .value = value,
97         };
98         return drmCommandWrite(dev->fd, DRM_OMAP_SET_PARAM, &req, sizeof(req));
99 }
100
101 /* allocate a new buffer object */
102 static struct omap_bo * omap_bo_new_impl(struct omap_device *dev,
103                 union omap_gem_size size, uint32_t flags)
104 {
105         struct omap_bo *bo = NULL;
106         struct drm_omap_gem_new req = {
107                         .size = size,
108                         .flags = flags,
109         };
110
111         if (size.bytes == 0) {
112                 goto fail;
113         }
114
115         bo = calloc(sizeof(*bo), 1);
116         if (!bo) {
117                 goto fail;
118         }
119
120         bo->dev = dev;
121
122         if (flags & OMAP_BO_TILED) {
123                 bo->size = round_up(size.tiled.width, PAGE_SIZE) * size.tiled.height;
124         } else {
125                 bo->size = size.bytes;
126         }
127
128         if (drmCommandWriteRead(dev->fd, DRM_OMAP_GEM_NEW, &req, sizeof(req))) {
129                 goto fail;
130         }
131
132         bo->handle = req.handle;
133
134         return bo;
135
136 fail:
137         free(bo);
138         return NULL;
139 }
140
141
142 /* allocate a new (un-tiled) buffer object */
143 struct omap_bo * omap_bo_new(struct omap_device *dev,
144                 uint32_t size, uint32_t flags)
145 {
146         union omap_gem_size gsize = {
147                         .bytes = size,
148         };
149         if (flags & OMAP_BO_TILED) {
150                 return NULL;
151         }
152         return omap_bo_new_impl(dev, gsize, flags);
153 }
154
155 /* allocate a new buffer object */
156 struct omap_bo * omap_bo_new_tiled(struct omap_device *dev,
157                 uint32_t width, uint32_t height, uint32_t flags)
158 {
159         union omap_gem_size gsize = {
160                         .tiled = {
161                                 .width = width,
162                                 .height = height,
163                         },
164         };
165         if (!(flags & OMAP_BO_TILED)) {
166                 return NULL;
167         }
168         return omap_bo_new_impl(dev, gsize, flags);
169 }
170
171 /* get buffer info */
172 static int get_buffer_info(struct omap_bo *bo)
173 {
174         struct drm_omap_gem_info req = {
175                         .handle = bo->handle,
176         };
177         int ret = drmCommandWriteRead(bo->dev->fd, DRM_OMAP_GEM_INFO,
178                         &req, sizeof(req));
179         if (ret) {
180                 return ret;
181         }
182
183         /* really all we need for now is mmap offset */
184         bo->offset = req.offset;
185         bo->size = req.size;
186
187         return 0;
188 }
189
190 /* import a buffer object from DRI2 name */
191 struct omap_bo * omap_bo_from_name(struct omap_device *dev, uint32_t name)
192 {
193         struct omap_bo *bo;
194         struct drm_gem_open req = {
195                         .name = name,
196         };
197
198         bo = calloc(sizeof(*bo), 1);
199         if (!bo) {
200                 goto fail;
201         }
202
203         if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) {
204                 goto fail;
205         }
206
207         bo->dev = dev;
208         bo->name = name;
209         bo->handle = req.handle;
210
211         return bo;
212
213 fail:
214         free(bo);
215         return NULL;
216 }
217
218 /* destroy a buffer object */
219 void omap_bo_del(struct omap_bo *bo)
220 {
221         if (!bo) {
222                 return;
223         }
224
225         if (bo->map) {
226                 munmap(bo->map, bo->size);
227         }
228
229         if (bo->handle) {
230                 struct drm_gem_close req = {
231                                 .handle = bo->handle,
232                 };
233
234                 drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
235         }
236
237         free(bo);
238 }
239
240 /* get the global flink/DRI2 buffer name */
241 int omap_bo_get_name(struct omap_bo *bo, uint32_t *name)
242 {
243         if (!bo->name) {
244                 struct drm_gem_flink req = {
245                                 .handle = bo->handle,
246                 };
247                 int ret;
248
249                 ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
250                 if (ret) {
251                         return ret;
252                 }
253
254                 bo->name = req.name;
255         }
256
257         *name = bo->name;
258
259         return 0;
260 }
261
262 uint32_t omap_bo_handle(struct omap_bo *bo)
263 {
264         return bo->handle;
265 }
266
267 uint32_t omap_bo_size(struct omap_bo *bo)
268 {
269         if (!bo->size) {
270                 get_buffer_info(bo);
271         }
272         return bo->size;
273 }
274
275 void * omap_bo_map(struct omap_bo *bo)
276 {
277         if (!bo->map) {
278                 if (!bo->offset) {
279                         get_buffer_info(bo);
280                 }
281
282                 bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE,
283                                 MAP_SHARED, bo->dev->fd, bo->offset);
284                 if (bo->map == MAP_FAILED) {
285                         bo->map = NULL;
286                 }
287         }
288         return bo->map;
289 }
290
291 int omap_bo_cpu_prep(struct omap_bo *bo, enum omap_gem_op op)
292 {
293         struct drm_omap_gem_cpu_prep req = {
294                         .handle = bo->handle,
295                         .op = op,
296         };
297         return drmCommandWrite(bo->dev->fd,
298                         DRM_OMAP_GEM_CPU_PREP, &req, sizeof(req));
299 }
300
301 int omap_bo_cpu_fini(struct omap_bo *bo, enum omap_gem_op op)
302 {
303         struct drm_omap_gem_cpu_fini req = {
304                         .handle = bo->handle,
305                         .op = op,
306                         .nregions = 0,
307         };
308         return drmCommandWrite(bo->dev->fd,
309                         DRM_OMAP_GEM_CPU_FINI, &req, sizeof(req));
310 }