exynos: support DRM_IOCTL_EXYNOS_GEM_MAP
[platform/upstream/libdrm.git] / libkms / exynos.c
1 /* exynos.c
2  *
3  * Copyright 2009 Samsung Electronics Co., Ltd.
4  * Authors:
5  *      SooChan Lim <sc1.lim@samsung.com>
6  *      Sangjin LEE <lsj119@samsung.com>
7  *
8  * This program is free software; you can redistribute  it and/or modify it
9  * under  the terms of  the GNU General  Public License as published by the
10  * Free Software Foundation;  either version 2 of the  License, or (at your
11  * option) any later version.
12  */
13
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17
18 #include <errno.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "internal.h"
23
24 #include <sys/mman.h>
25 #include <sys/ioctl.h>
26 #include "xf86drm.h"
27
28 #include "libdrm.h"
29 #include "exynos_drm.h"
30
31 struct exynos_bo
32 {
33         struct kms_bo base;
34         unsigned map_count;
35 };
36
37 static int
38 exynos_get_prop(struct kms_driver *kms, unsigned key, unsigned *out)
39 {
40         switch (key) {
41         case KMS_BO_TYPE:
42                 *out = KMS_BO_TYPE_SCANOUT_X8R8G8B8 | KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8;
43                 break;
44         default:
45                 return -EINVAL;
46         }
47         return 0;
48 }
49
50 static int
51 exynos_destroy(struct kms_driver *kms)
52 {
53         free(kms);
54         return 0;
55 }
56
57 static int
58 exynos_bo_create(struct kms_driver *kms,
59                  const unsigned width, const unsigned height,
60                  const enum kms_bo_type type, const unsigned *attr,
61                  struct kms_bo **out)
62 {
63         struct drm_exynos_gem_create arg;
64         unsigned size, pitch;
65         struct exynos_bo *bo;
66         int i, ret;
67
68         for (i = 0; attr[i]; i += 2) {
69                 switch (attr[i]) {
70                 case KMS_WIDTH:
71                 case KMS_HEIGHT:
72                 case KMS_BO_TYPE:
73                         break;
74                 default:
75                         return -EINVAL;
76                 }
77         }
78
79         bo = calloc(1, sizeof(*bo));
80         if (!bo)
81                 return -ENOMEM;
82
83         if (type == KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8) {
84                 pitch = 64 * 4;
85                 size = 64 * 64 * 4;
86         } else if (type == KMS_BO_TYPE_SCANOUT_X8R8G8B8) {
87                 pitch = width * 4;
88                 pitch = (pitch + 512 - 1) & ~(512 - 1);
89                 size = pitch * ((height + 4 - 1) & ~(4 - 1));
90         } else {
91                 return -EINVAL;
92         }
93
94         memset(&arg, 0, sizeof(arg));
95         arg.size = size;
96
97         ret = drmCommandWriteRead(kms->fd, DRM_EXYNOS_GEM_CREATE, &arg, sizeof(arg));
98         if (ret)
99                 goto err_free;
100
101         bo->base.kms = kms;
102         bo->base.handle = arg.handle;
103         bo->base.size = size;
104         bo->base.pitch = pitch;
105
106         *out = &bo->base;
107
108         return 0;
109
110 err_free:
111         free(bo);
112         return ret;
113 }
114
115 static int
116 exynos_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out)
117 {
118         switch (key) {
119         default:
120                 return -EINVAL;
121         }
122 }
123
124 static int
125 exynos_bo_map(struct kms_bo *_bo, void **out)
126 {
127         struct exynos_bo *bo = (struct exynos_bo *)_bo;
128         struct drm_exynos_gem_map arg;
129         void *map = NULL;
130         int ret;
131
132         if (bo->base.ptr) {
133                 bo->map_count++;
134                 *out = bo->base.ptr;
135                 return 0;
136         }
137
138         memset(&arg, 0, sizeof(arg));
139         arg.handle = bo->base.handle;
140
141         ret = drmIoctl(bo->base.kms->fd, DRM_IOCTL_EXYNOS_GEM_MAP, &arg);
142         if (ret)
143                 return ret;
144
145         map = drm_mmap(0, bo->base.size, PROT_READ | PROT_WRITE, MAP_SHARED, bo->base.kms->fd, arg.offset);
146         if (map == MAP_FAILED)
147                 return -errno;
148
149         bo->base.ptr = map;
150         bo->map_count++;
151         *out = bo->base.ptr;
152
153         return 0;
154 }
155
156 static int
157 exynos_bo_unmap(struct kms_bo *_bo)
158 {
159         struct exynos_bo *bo = (struct exynos_bo *)_bo;
160         bo->map_count--;
161         return 0;
162 }
163
164 static int
165 exynos_bo_destroy(struct kms_bo *_bo)
166 {
167         struct exynos_bo *bo = (struct exynos_bo *)_bo;
168         struct drm_gem_close arg;
169         int ret;
170
171         if (bo->base.ptr) {
172                 /* XXX Sanity check map_count */
173                 munmap(bo->base.ptr, bo->base.size);
174                 bo->base.ptr = NULL;
175         }
176
177         memset(&arg, 0, sizeof(arg));
178         arg.handle = bo->base.handle;
179
180         ret = drmIoctl(bo->base.kms->fd, DRM_IOCTL_GEM_CLOSE, &arg);
181         if (ret)
182                 return -errno;
183
184         free(bo);
185         return 0;
186 }
187
188 int
189 exynos_create(int fd, struct kms_driver **out)
190 {
191         struct kms_driver *kms;
192
193         kms = calloc(1, sizeof(*kms));
194         if (!kms)
195                 return -ENOMEM;
196
197         kms->fd = fd;
198
199         kms->bo_create = exynos_bo_create;
200         kms->bo_map = exynos_bo_map;
201         kms->bo_unmap = exynos_bo_unmap;
202         kms->bo_get_prop = exynos_bo_get_prop;
203         kms->bo_destroy = exynos_bo_destroy;
204         kms->get_prop = exynos_get_prop;
205         kms->destroy = exynos_destroy;
206         *out = kms;
207
208         return 0;
209 }