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_macros.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
exynos_get_prop(struct kms_driver * kms,unsigned key,unsigned * out)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
exynos_destroy(struct kms_driver * kms)51 exynos_destroy(struct kms_driver *kms)
52 {
53 free(kms);
54 return 0;
55 }
56
57 static int
exynos_bo_create(struct kms_driver * kms,const unsigned width,const unsigned height,const enum kms_bo_type type,const unsigned * attr,struct kms_bo ** out)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
exynos_bo_get_prop(struct kms_bo * bo,unsigned key,unsigned * out)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
exynos_bo_map(struct kms_bo * _bo,void ** out)125 exynos_bo_map(struct kms_bo *_bo, void **out)
126 {
127 struct exynos_bo *bo = (struct exynos_bo *)_bo;
128 struct drm_mode_map_dumb 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_MODE_MAP_DUMB, &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
exynos_bo_unmap(struct kms_bo * _bo)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
exynos_bo_destroy(struct kms_bo * _bo)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 drm_private int
exynos_create(int fd,struct kms_driver ** out)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 }
210