2 * Copyright (C) 2016 Nexell Co., Ltd.
3 * Author: SeongO, Park <ray@nexell.co.kr>
17 #include <sys/types.h>
19 #include <sys/ioctl.h>
20 #include <sys/mman.h> // PROT_READ/PROT_WRITE/MAP_SHARED/mmap/munmap
22 #include <nexell/nexell_drm.h>
23 #include <nx_video_alloc.h>
25 #include <libdrm/drm_fourcc.h>
26 #include <linux/videodev2.h>
27 #include <linux/videodev2_nxp_media.h>
28 #ifdef TIZEN_FEATURE_ARTIK530
29 #include <tbm_bufmgr.h>
32 #define DRM_DEVICE_NAME "/dev/dri/card0"
34 #define DRM_IOCTL_NR(n) _IOC_NR(n)
35 #define DRM_IOC_VOID _IOC_NONE
36 #define DRM_IOC_READ _IOC_READ
37 #define DRM_IOC_WRITE _IOC_WRITE
38 #define DRM_IOC_READWRITE _IOC_READ|_IOC_WRITE
39 #define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
42 drm_ioctl (int32_t drm_fd, uint32_t request, void *arg)
47 ret = ioctl (drm_fd, request, arg);
48 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
53 drm_command_write_read (int fd, uint32_t command_index,
54 void *data, uint32_t size)
58 request = DRM_IOC (DRM_IOC_READ | DRM_IOC_WRITE, DRM_IOCTL_BASE,
59 DRM_COMMAND_BASE + command_index, size);
60 if (drm_ioctl (fd, request, data))
69 alloc_gem (int drm_fd, int size, int flags)
71 struct nx_drm_gem_create arg = { 0, };
74 arg.size = (uint32_t) size;
77 ret = drm_command_write_read (drm_fd, DRM_NX_GEM_CREATE, &arg, sizeof (arg));
79 perror ("drm_command_write_read\n");
82 //printf("[DRM ALLOC] gem %d, size %d, flags 0x%x\n", arg.handle, size, flags);
88 free_gem (int drm_fd, int gem)
90 struct drm_gem_close arg = { 0, };
93 drm_ioctl (drm_fd, DRM_IOCTL_GEM_CLOSE, &arg);
100 gem_to_dmafd (int drm_fd, int gem_fd)
103 struct drm_prime_handle arg = { 0, };
106 arg.flags = O_CLOEXEC | O_RDWR;
107 ret = drm_ioctl (drm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg);
109 printf ("fail : get fd from gem:%d (DRM_IOCTL_PRIME_HANDLE_TO_FD)\n", ret);
116 get_flink_name (int fd, int gem)
118 struct drm_gem_flink arg = { 0, };
121 if (drm_ioctl (fd, DRM_IOCTL_GEM_FLINK, &arg)) {
122 printf ("fail : get flink from gem:%d (DRM_IOCTL_GEM_FLINK)\n", gem);
129 gem_from_flink (int fd, uint32_t flink_name)
131 struct drm_gem_open arg = { 0, };
132 /* struct nx_drm_gem_info info = { 0, }; */
134 arg.name = flink_name;
135 if (drm_ioctl (fd, DRM_IOCTL_GEM_OPEN, &arg)) {
136 printf ("fail : cannot open gem name=%d\n", flink_name);
144 // Nexell Private Video Memory Allocator for DRM
148 #define ALIGN(X,N) ( (X+N-1) & (~(N-1)) )
151 #define ALIGNED16(X) ALIGN(X,16)
154 // Nexell Private Memory Allocator
156 NX_AllocateMemory (int size, int align)
161 NX_MEMORY_INFO *pMem;
163 int drmFd = open (DRM_DEVICE_NAME, O_RDWR);
167 drmDropMaster (drmFd);
169 gemFd = alloc_gem (drmFd, size, flags);
173 dmaFd = gem_to_dmafd (drmFd, gemFd);
177 pMem = (NX_MEMORY_INFO *) calloc (1, sizeof (NX_MEMORY_INFO));
181 pMem->flink = get_flink_name (drmFd, gemFd);
188 free_gem (drmFd, gemFd);
196 NX_FreeMemory (NX_MEMORY_INFO * pMem)
200 munmap (pMem->pBuffer, pMem->size);
203 free_gem (pMem->drmFd, pMem->gemFd);
211 // Video Specific Allocator Wrapper
213 // Suport Format & Planes
215 // 1 Plane : I420, NV12
220 NX_AllocateVideoMemory (int width, int height, int32_t planes, uint32_t format,
223 int gemFd[NX_MAX_PLANES] = { 0, };
224 int dmaFd[NX_MAX_PLANES] = { 0, };
225 int32_t flags = 0, i = 0;
226 int32_t luStride, cStride;
227 int32_t luVStride, cVStride;
228 int32_t stride[NX_MAX_PLANES];
229 int32_t size[NX_MAX_PLANES];
230 uint32_t flink[NX_MAX_PLANES];
232 NX_VID_MEMORY_INFO *pVidMem;
234 int drmFd = open (DRM_DEVICE_NAME, O_RDWR);
238 drmDropMaster (drmFd);
241 luStride = ALIGN (width, 32);
242 luVStride = ALIGN (height, 16);
246 case DRM_FORMAT_YUV420:
247 case DRM_FORMAT_NV12:
248 case DRM_FORMAT_NV21:
249 case V4L2_PIX_FMT_YUV420M:
250 case V4L2_PIX_FMT_NV12M:
251 case V4L2_PIX_FMT_NV21M:
252 cStride = luStride / 2;
253 cVStride = ALIGN (height / 2, 16);
256 case DRM_FORMAT_YUV422:
257 case DRM_FORMAT_NV16:
258 case DRM_FORMAT_NV61:
259 case V4L2_PIX_FMT_YUV422M:
260 #if 0 // Disabled by DIGNSYS
261 case V4L2_PIX_FMT_NV16M:
262 case V4L2_PIX_FMT_NV61M:
264 cStride = luStride / 2;
265 cVStride = luVStride;
268 case DRM_FORMAT_YUV444:
269 //case DRM_FORMAT_NV24:
270 //case DRM_FORMAT_NV42:
271 case V4L2_PIX_FMT_YUV444M:
272 case V4L2_PIX_FMT_NV24M:
273 case V4L2_PIX_FMT_NV42M:
275 cVStride = luVStride;
278 case V4L2_PIX_FMT_GREY:
283 printf ("Unknown format type\n");
287 // Decide Memory Size
290 size[0] = luStride * luVStride + cStride * cVStride * 2;
291 stride[0] = luStride;
292 gemFd[0] = alloc_gem (drmFd, size[0], flags);
295 dmaFd[0] = gem_to_dmafd (drmFd, gemFd[0]);
298 flink[0] = get_flink_name (drmFd, gemFd[0]);
302 size[0] = luStride * luVStride;
303 stride[0] = luStride;
304 gemFd[0] = alloc_gem (drmFd, size[0], flags);
307 dmaFd[0] = gem_to_dmafd (drmFd, gemFd[0]);
310 flink[0] = get_flink_name (drmFd, gemFd[0]);
313 size[1] = cStride * cVStride * 2;
314 stride[1] = cStride * 2;
315 gemFd[1] = alloc_gem (drmFd, size[1], flags);
318 dmaFd[1] = gem_to_dmafd (drmFd, gemFd[1]);
321 flink[1] = get_flink_name (drmFd, gemFd[1]);
325 size[0] = luStride * luVStride;
326 stride[0] = luStride;
327 gemFd[0] = alloc_gem (drmFd, size[0], flags);
330 dmaFd[0] = gem_to_dmafd (drmFd, gemFd[0]);
333 flink[0] = get_flink_name (drmFd, gemFd[0]);
336 size[1] = cStride * cVStride;
338 gemFd[1] = alloc_gem (drmFd, size[1], flags);
341 dmaFd[1] = gem_to_dmafd (drmFd, gemFd[1]);
344 flink[1] = get_flink_name (drmFd, gemFd[1]);
347 size[2] = cStride * cVStride;
349 gemFd[2] = alloc_gem (drmFd, size[2], flags);
352 dmaFd[2] = gem_to_dmafd (drmFd, gemFd[2]);
355 flink[2] = get_flink_name (drmFd, gemFd[2]);
360 pVidMem = (NX_VID_MEMORY_INFO *) calloc (1, sizeof (NX_VID_MEMORY_INFO));
364 #ifdef TIZEN_FEATURE_ARTIK530
365 pVidMem->bufmgr = tbm_bufmgr_init (drmFd);
366 if (!pVidMem->bufmgr)
370 pVidMem->width = width;
371 pVidMem->height = height;
372 pVidMem->align = align;
373 pVidMem->planes = planes;
374 pVidMem->format = format;
375 pVidMem->drmFd = drmFd;
376 for (i = 0; i < planes; i++) {
377 pVidMem->dmaFd[i] = dmaFd[i];
378 pVidMem->gemFd[i] = gemFd[i];
379 pVidMem->size[i] = size[i];
380 pVidMem->stride[i] = stride[i];
381 pVidMem->flink[i] = flink[i];
382 #ifdef TIZEN_FEATURE_ARTIK530
383 pVidMem->bo[i] = tbm_bo_import (pVidMem->bufmgr, flink[i]);
390 #ifdef TIZEN_FEATURE_ARTIK530
392 for (i = 0; i < planes; i++) {
394 tbm_bo_unref (pVidMem->bo[i]);
399 for (i = 0; i < planes; i++) {
401 free_gem (drmFd, gemFd[i]);
408 #ifdef TIZEN_FEATURE_ARTIK530
410 tbm_bufmgr_deinit (pVidMem->bufmgr);
421 NX_FreeVideoMemory (NX_VID_MEMORY_INFO * pMem)
425 for (i = 0; i < pMem->planes; i++) {
426 #ifdef TIZEN_FEATURE_ARTIK530
428 tbm_bo_unref (pMem->bo[i]);
430 if (pMem->pBuffer[i]) {
431 munmap (pMem->pBuffer[i], pMem->size[i]);
433 free_gem (pMem->drmFd, pMem->gemFd[i]);
434 close (pMem->dmaFd[i]);
436 #ifdef TIZEN_FEATURE_ARTIK530
438 tbm_bufmgr_deinit (pMem->bufmgr);
447 // Memory Mapping/Unmapping Memory
450 NX_MapMemory (NX_MEMORY_INFO * pMem)
461 mmap (0, pMem->size, PROT_READ | PROT_WRITE, MAP_SHARED, pMem->dmaFd, 0);
462 if (pBuf == MAP_FAILED) {
463 printf("Map failed : size %d, fd %d, error : %s\n", pMem->size, pMem->dmaFd, strerror(errno));
466 pMem->pBuffer = pBuf;
472 NX_UnmapMemory (NX_MEMORY_INFO * pMem)
480 if (0 != munmap (pMem->pBuffer, pMem->size))
483 pMem->pBuffer = NULL;
488 NX_MapVideoMemory (NX_VID_MEMORY_INFO * pMem)
496 for (i = 0; i < pMem->planes; i++) {
497 if (pMem->pBuffer[i])
501 mmap (0, pMem->size[i], PROT_READ | PROT_WRITE, MAP_SHARED,
503 if (pBuf == MAP_FAILED) {
507 pMem->pBuffer[i] = pBuf;
513 NX_UnmapVideoMemory (NX_VID_MEMORY_INFO * pMem)
518 for (i = 0; i < pMem->planes; i++) {
519 if (pMem->pBuffer[i]) {
520 munmap (pMem->pBuffer[i], pMem->size[i]);
528 NX_GetGEMHandles (int drmFd, NX_VID_MEMORY_INFO * pMem,
529 uint32_t handles[NX_MAX_PLANES])
532 memset (handles, 0, sizeof (uint32_t) * NX_MAX_PLANES);
534 for (i = 0; i < pMem->planes; i++) {
535 handles[i] = gem_from_flink (drmFd, pMem->flink[i]);
536 if (0 > (int) handles[i]) {
544 NX_GetGemHandle (int drmFd, NX_VID_MEMORY_INFO * pMem, int32_t plane)
546 if (plane >= NX_MAX_PLANES || plane < 0)
549 return gem_from_flink (drmFd, pMem->flink[plane]);