xref: /OK3568_Linux_fs/external/mpp/osal/allocator/allocator_drm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright 2010 Rockchip Electronics S.LSI Co. LTD
3  *
4  * Licensed under the Apache License, Versdrm 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITDRMS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissdrms and
14  * limitatdrms under the License.
15  */
16 
17 #define MODULE_TAG "mpp_drm"
18 
19 #include <unistd.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <sys/ioctl.h>
24 #include <sys/mman.h>
25 
26 #include <linux/drm.h>
27 #include <linux/drm_mode.h>
28 
29 #include "os_mem.h"
30 #include "allocator_drm.h"
31 
32 #include "mpp_env.h"
33 #include "mpp_mem.h"
34 #include "mpp_debug.h"
35 #include "mpp_common.h"
36 #include "mpp_runtime.h"
37 
38 static RK_U32 drm_debug = 0;
39 
40 #define DRM_FUNCTION                (0x00000001)
41 #define DRM_DEVICE                  (0x00000002)
42 #define DRM_CLIENT                  (0x00000004)
43 #define DRM_IOCTL                   (0x00000008)
44 
45 #define drm_dbg(flag, fmt, ...)     _mpp_dbg_f(drm_debug, flag, fmt, ## __VA_ARGS__)
46 #define drm_dbg_func(fmt, ...)      drm_dbg(DRM_FUNCTION, fmt, ## __VA_ARGS__)
47 
48 typedef struct {
49     RK_U32  alignment;
50     RK_S32  drm_device;
51     RK_U32  flags;
52 } allocator_ctx_drm;
53 
54 static const char *dev_drm = "/dev/dri/card0";
55 
drm_ioctl(int fd,int req,void * arg)56 static int drm_ioctl(int fd, int req, void *arg)
57 {
58     int ret;
59 
60     do {
61         ret = ioctl(fd, req, arg);
62     } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
63 
64     drm_dbg(DRM_IOCTL, "%x with code %d: %s\n", req,
65             ret, strerror(errno));
66 
67     return ret;
68 }
69 
drm_handle_to_fd(int fd,RK_U32 handle,int * map_fd,RK_U32 flags)70 static int drm_handle_to_fd(int fd, RK_U32 handle, int *map_fd, RK_U32 flags)
71 {
72     int ret;
73     struct drm_prime_handle dph;
74 
75     memset(&dph, 0, sizeof(struct drm_prime_handle));
76     dph.handle = handle;
77     dph.fd = -1;
78     dph.flags = flags;
79 
80     if (map_fd == NULL)
81         return -EINVAL;
82 
83     ret = drm_ioctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &dph);
84     if (ret < 0)
85         return ret;
86 
87     *map_fd = dph.fd;
88 
89     drm_dbg_func("dev %d handle %d get fd %d\n", fd, handle, *map_fd);
90 
91     if (*map_fd < 0) {
92         mpp_err_f("map ioctl returned negative fd\n");
93         return -EINVAL;
94     }
95 
96     return ret;
97 }
98 
drm_alloc(int fd,size_t len,size_t align,RK_U32 * handle,RK_U32 flags)99 static int drm_alloc(int fd, size_t len, size_t align, RK_U32 *handle, RK_U32 flags)
100 {
101     int ret;
102     struct drm_mode_create_dumb dmcb;
103 
104     memset(&dmcb, 0, sizeof(struct drm_mode_create_dumb));
105     dmcb.bpp = 8;
106     dmcb.width = (len + align - 1) & (~(align - 1));
107     dmcb.height = 1;
108     dmcb.flags = flags;
109 
110     if (handle == NULL)
111         return -EINVAL;
112 
113     ret = drm_ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &dmcb);
114     if (ret < 0)
115         return ret;
116 
117     *handle = dmcb.handle;
118     drm_dbg_func("dev %d alloc aligned %d handle %d size %lld\n", fd,
119                  align, dmcb.handle, dmcb.size);
120 
121     return ret;
122 }
123 
drm_free(int fd,RK_U32 handle)124 static int drm_free(int fd, RK_U32 handle)
125 {
126     struct drm_mode_destroy_dumb data = {
127         .handle = handle,
128     };
129     return drm_ioctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &data);
130 }
131 
os_allocator_drm_open(void ** ctx,MppAllocatorCfg * cfg)132 static MPP_RET os_allocator_drm_open(void **ctx, MppAllocatorCfg *cfg)
133 {
134     RK_S32 fd;
135     allocator_ctx_drm *p;
136 
137     drm_dbg_func("enter\n");
138 
139     if (NULL == ctx) {
140         mpp_err_f("does not accept NULL input\n");
141         return MPP_ERR_NULL_PTR;
142     }
143 
144     *ctx = NULL;
145 
146     mpp_env_get_u32("drm_debug", &drm_debug, 0);
147 
148     fd = open(dev_drm, O_RDWR | O_CLOEXEC);
149     if (fd < 0) {
150         mpp_err_f("open %s failed!\n", dev_drm);
151         return MPP_ERR_UNKNOW;
152     }
153 
154     drm_dbg(DRM_DEVICE, "open drm dev fd %d\n", fd);
155 
156     p = mpp_malloc(allocator_ctx_drm, 1);
157     if (NULL == p) {
158         close(fd);
159         mpp_err_f("failed to allocate context\n");
160         return MPP_ERR_MALLOC;
161     } else {
162         /*
163          * default drm use cma, do nothing here
164          */
165         p->alignment    = cfg->alignment;
166         p->flags        = cfg->flags;
167         p->drm_device   = fd;
168         *ctx = p;
169     }
170 
171     drm_dbg_func("leave dev %d\n", fd);
172 
173     return MPP_OK;
174 }
175 
os_allocator_drm_alloc(void * ctx,MppBufferInfo * info)176 static MPP_RET os_allocator_drm_alloc(void *ctx, MppBufferInfo *info)
177 {
178     MPP_RET ret = MPP_OK;
179     allocator_ctx_drm *p = NULL;
180 
181     if (NULL == ctx) {
182         mpp_err_f("does not accept NULL input\n");
183         return MPP_ERR_NULL_PTR;
184     }
185 
186     p = (allocator_ctx_drm *)ctx;
187 
188     drm_dbg_func("dev %d alloc alignment %d size %d\n", p->drm_device,
189                  p->alignment, info->size);
190 
191     ret = drm_alloc(p->drm_device, info->size, p->alignment,
192                     (RK_U32 *)&info->hnd, p->flags);
193     if (ret) {
194         mpp_err_f("drm_alloc failed ret %d\n", ret);
195         return ret;
196     }
197 
198     ret = drm_handle_to_fd(p->drm_device, (RK_U32)((intptr_t)info->hnd),
199                            &info->fd, DRM_CLOEXEC | DRM_RDWR);
200 
201     if (ret) {
202         mpp_err_f("handle_to_fd failed ret %d\n", ret);
203         return ret;
204     }
205 
206     drm_dbg_func("dev %d get handle %d with fd %d\n", p->drm_device,
207                  (RK_U32)((intptr_t)info->hnd), info->fd);
208 
209     /* release handle to reduce iova usage */
210     drm_free(p->drm_device, (RK_U32)((intptr_t)info->hnd));
211     info->hnd = NULL;
212     info->ptr = NULL;
213 
214     return ret;
215 }
216 
os_allocator_drm_import(void * ctx,MppBufferInfo * data)217 static MPP_RET os_allocator_drm_import(void *ctx, MppBufferInfo *data)
218 {
219     allocator_ctx_drm *p = (allocator_ctx_drm *)ctx;
220     RK_S32 fd_ext = data->fd;
221     MPP_RET ret = MPP_OK;
222 
223     drm_dbg_func("enter dev %d\n", p->drm_device);
224 
225     mpp_assert(fd_ext > 0);
226 
227     data->fd = dup(fd_ext);
228     data->ptr = NULL;
229 
230     if (data->fd <= 0) {
231         mpp_err_f(" fd dup return invalid fd %d\n", data->fd);
232         ret = MPP_NOK;
233     }
234 
235     drm_dbg_func("leave dev %d\n", p->drm_device);
236 
237     return ret;
238 }
239 
os_allocator_drm_free(void * ctx,MppBufferInfo * data)240 static MPP_RET os_allocator_drm_free(void *ctx, MppBufferInfo *data)
241 {
242     allocator_ctx_drm *p = NULL;
243 
244     if (NULL == ctx) {
245         mpp_err_f("does not accept NULL input\n");
246         return MPP_ERR_NULL_PTR;
247     }
248 
249     p = (allocator_ctx_drm *)ctx;
250 
251     drm_dbg_func("dev %d handle %p unmap %p fd %d size %d\n", p->drm_device,
252                  data->hnd, data->ptr, data->fd, data->size);
253 
254     if (data->ptr) {
255         munmap(data->ptr, data->size);
256         data->ptr = NULL;
257     }
258 
259     if (data->fd > 0) {
260         close(data->fd);
261         data->fd = -1;
262     } else {
263         mpp_err_f("can not close invalid fd %d\n", data->fd);
264     }
265 
266     return MPP_OK;
267 }
268 
os_allocator_drm_close(void * ctx)269 static MPP_RET os_allocator_drm_close(void *ctx)
270 {
271     int ret;
272     allocator_ctx_drm *p;
273 
274     if (NULL == ctx) {
275         mpp_err("os_allocator_close doesn't accept NULL input\n");
276         return MPP_ERR_NULL_PTR;
277     }
278 
279     p = (allocator_ctx_drm *)ctx;
280     drm_dbg_func("dev %d", p->drm_device);
281 
282     ret = close(p->drm_device);
283     mpp_free(p);
284     if (ret < 0)
285         return (MPP_RET) - errno;
286 
287     return MPP_OK;
288 }
289 
os_allocator_drm_mmap(void * ctx,MppBufferInfo * data)290 static MPP_RET os_allocator_drm_mmap(void *ctx, MppBufferInfo *data)
291 {
292     allocator_ctx_drm *p;
293     MPP_RET ret = MPP_OK;
294     if (NULL == ctx) {
295         mpp_err("os_allocator_close do not accept NULL input\n");
296         return MPP_ERR_NULL_PTR;
297     }
298     p = (allocator_ctx_drm *)ctx;
299 
300     if (NULL == ctx)
301         return MPP_ERR_NULL_PTR;
302 
303     if (NULL == data->ptr) {
304         int flags = PROT_READ;
305 
306         if (fcntl(data->fd, F_GETFL) & O_RDWR)
307             flags |= PROT_WRITE;
308 
309         data->ptr = mmap(NULL, data->size, flags, MAP_SHARED, data->fd, 0);
310         if (data->ptr == MAP_FAILED) {
311             mpp_err("mmap failed: %s\n", strerror(errno));
312             data->ptr = NULL;
313             return -errno;
314         }
315 
316         drm_dbg_func("dev %d mmap fd %d to %p (%s)\n", p->drm_device,
317                      data->fd, data->ptr,
318                      flags & PROT_WRITE ? "RDWR" : "RDONLY");
319     }
320 
321     return ret;
322 }
323 
324 os_allocator allocator_drm = {
325     .type = MPP_BUFFER_TYPE_DRM,
326     .open = os_allocator_drm_open,
327     .close = os_allocator_drm_close,
328     .alloc = os_allocator_drm_alloc,
329     .free = os_allocator_drm_free,
330     .import = os_allocator_drm_import,
331     .release = os_allocator_drm_free,
332     .mmap = os_allocator_drm_mmap,
333 };
334