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