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 "exynos_drm.h"
29 
30 struct exynos_bo
31 {
32 	struct kms_bo base;
33 	unsigned map_count;
34 };
35 
36 static int
exynos_get_prop(struct kms_driver * kms,unsigned key,unsigned * out)37 exynos_get_prop(struct kms_driver *kms, unsigned key, unsigned *out)
38 {
39 	switch (key) {
40 	case KMS_BO_TYPE:
41 		*out = KMS_BO_TYPE_SCANOUT_X8R8G8B8 | KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8;
42 		break;
43 	default:
44 		return -EINVAL;
45 	}
46 	return 0;
47 }
48 
49 static int
exynos_destroy(struct kms_driver * kms)50 exynos_destroy(struct kms_driver *kms)
51 {
52 	free(kms);
53 	return 0;
54 }
55 
56 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)57 exynos_bo_create(struct kms_driver *kms,
58 		 const unsigned width, const unsigned height,
59 		 const enum kms_bo_type type, const unsigned *attr,
60 		 struct kms_bo **out)
61 {
62 	struct drm_exynos_gem_create arg;
63 	unsigned size, pitch;
64 	struct exynos_bo *bo;
65 	int i, ret;
66 
67 	for (i = 0; attr[i]; i += 2) {
68 		switch (attr[i]) {
69 		case KMS_WIDTH:
70 		case KMS_HEIGHT:
71 		case KMS_BO_TYPE:
72 			break;
73 		default:
74 			return -EINVAL;
75 		}
76 	}
77 
78 	bo = calloc(1, sizeof(*bo));
79 	if (!bo)
80 		return -ENOMEM;
81 
82 	if (type == KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8) {
83 		pitch = 64 * 4;
84 		size = 64 * 64 * 4;
85 	} else if (type == KMS_BO_TYPE_SCANOUT_X8R8G8B8) {
86 		pitch = width * 4;
87 		pitch = (pitch + 512 - 1) & ~(512 - 1);
88 		size = pitch * ((height + 4 - 1) & ~(4 - 1));
89 	} else {
90 		return -EINVAL;
91 	}
92 
93 	memset(&arg, 0, sizeof(arg));
94 	arg.size = size;
95 
96 	ret = drmCommandWriteRead(kms->fd, DRM_EXYNOS_GEM_CREATE, &arg, sizeof(arg));
97 	if (ret)
98 		goto err_free;
99 
100 	bo->base.kms = kms;
101 	bo->base.handle = arg.handle;
102 	bo->base.size = size;
103 	bo->base.pitch = pitch;
104 
105 	*out = &bo->base;
106 
107 	return 0;
108 
109 err_free:
110 	free(bo);
111 	return ret;
112 }
113 
114 static int
exynos_bo_get_prop(struct kms_bo * bo,unsigned key,unsigned * out)115 exynos_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out)
116 {
117 	switch (key) {
118 	default:
119 		return -EINVAL;
120 	}
121 }
122 
123 static int
exynos_bo_map(struct kms_bo * _bo,void ** out)124 exynos_bo_map(struct kms_bo *_bo, void **out)
125 {
126 	struct exynos_bo *bo = (struct exynos_bo *)_bo;
127 	struct drm_exynos_gem_map_off arg;
128 	void *map = NULL;
129 	int ret;
130 
131 	if (bo->base.ptr) {
132 		bo->map_count++;
133 		*out = bo->base.ptr;
134 		return 0;
135 	}
136 
137 	memset(&arg, 0, sizeof(arg));
138 	arg.handle = bo->base.handle;
139 
140 	ret = drmCommandWriteRead(bo->base.kms->fd, DRM_EXYNOS_GEM_MAP_OFFSET, &arg, sizeof(arg));
141 	if (ret)
142 		return ret;
143 
144 	map = mmap(0, bo->base.size, PROT_READ | PROT_WRITE, MAP_SHARED, bo->base.kms->fd, arg.offset);
145 	if (map == MAP_FAILED)
146 		return -errno;
147 
148 	bo->base.ptr = map;
149 	bo->map_count++;
150 	*out = bo->base.ptr;
151 
152 	return 0;
153 }
154 
155 static int
exynos_bo_unmap(struct kms_bo * _bo)156 exynos_bo_unmap(struct kms_bo *_bo)
157 {
158 	struct exynos_bo *bo = (struct exynos_bo *)_bo;
159 	bo->map_count--;
160 	return 0;
161 }
162 
163 static int
exynos_bo_destroy(struct kms_bo * _bo)164 exynos_bo_destroy(struct kms_bo *_bo)
165 {
166 	struct exynos_bo *bo = (struct exynos_bo *)_bo;
167 	struct drm_gem_close arg;
168 	int ret;
169 
170 	if (bo->base.ptr) {
171 		/* XXX Sanity check map_count */
172 		munmap(bo->base.ptr, bo->base.size);
173 		bo->base.ptr = NULL;
174 	}
175 
176 	memset(&arg, 0, sizeof(arg));
177 	arg.handle = bo->base.handle;
178 
179 	ret = drmIoctl(bo->base.kms->fd, DRM_IOCTL_GEM_CLOSE, &arg);
180 	if (ret)
181 		return -errno;
182 
183 	free(bo);
184 	return 0;
185 }
186 
187 int
exynos_create(int fd,struct kms_driver ** out)188 exynos_create(int fd, struct kms_driver **out)
189 {
190 	struct kms_driver *kms;
191 
192 	kms = calloc(1, sizeof(*kms));
193 	if (!kms)
194 		return -ENOMEM;
195 
196 	kms->fd = fd;
197 
198 	kms->bo_create = exynos_bo_create;
199 	kms->bo_map = exynos_bo_map;
200 	kms->bo_unmap = exynos_bo_unmap;
201 	kms->bo_get_prop = exynos_bo_get_prop;
202 	kms->bo_destroy = exynos_bo_destroy;
203 	kms->get_prop = exynos_get_prop;
204 	kms->destroy = exynos_destroy;
205 	*out = kms;
206 
207 	return 0;
208 }
209