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 		ret = -EINVAL;
92 		goto err_free;
93 	}
94 
95 	memset(&arg, 0, sizeof(arg));
96 	arg.size = size;
97 
98 	ret = drmCommandWriteRead(kms->fd, DRM_EXYNOS_GEM_CREATE, &arg, sizeof(arg));
99 	if (ret)
100 		goto err_free;
101 
102 	bo->base.kms = kms;
103 	bo->base.handle = arg.handle;
104 	bo->base.size = size;
105 	bo->base.pitch = pitch;
106 
107 	*out = &bo->base;
108 
109 	return 0;
110 
111 err_free:
112 	free(bo);
113 	return ret;
114 }
115 
116 static int
exynos_bo_get_prop(struct kms_bo * bo,unsigned key,unsigned * out)117 exynos_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out)
118 {
119 	switch (key) {
120 	default:
121 		return -EINVAL;
122 	}
123 }
124 
125 static int
exynos_bo_map(struct kms_bo * _bo,void ** out)126 exynos_bo_map(struct kms_bo *_bo, void **out)
127 {
128 	struct exynos_bo *bo = (struct exynos_bo *)_bo;
129 	struct drm_mode_map_dumb arg;
130 	void *map = NULL;
131 	int ret;
132 
133 	if (bo->base.ptr) {
134 		bo->map_count++;
135 		*out = bo->base.ptr;
136 		return 0;
137 	}
138 
139 	memset(&arg, 0, sizeof(arg));
140 	arg.handle = bo->base.handle;
141 
142 	ret = drmIoctl(bo->base.kms->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
143 	if (ret)
144 		return ret;
145 
146 	map = drm_mmap(0, bo->base.size, PROT_READ | PROT_WRITE, MAP_SHARED, bo->base.kms->fd, arg.offset);
147 	if (map == MAP_FAILED)
148 		return -errno;
149 
150 	bo->base.ptr = map;
151 	bo->map_count++;
152 	*out = bo->base.ptr;
153 
154 	return 0;
155 }
156 
157 static int
exynos_bo_unmap(struct kms_bo * _bo)158 exynos_bo_unmap(struct kms_bo *_bo)
159 {
160 	struct exynos_bo *bo = (struct exynos_bo *)_bo;
161 	bo->map_count--;
162 	return 0;
163 }
164 
165 static int
exynos_bo_destroy(struct kms_bo * _bo)166 exynos_bo_destroy(struct kms_bo *_bo)
167 {
168 	struct exynos_bo *bo = (struct exynos_bo *)_bo;
169 	struct drm_gem_close arg;
170 	int ret;
171 
172 	if (bo->base.ptr) {
173 		/* XXX Sanity check map_count */
174 		munmap(bo->base.ptr, bo->base.size);
175 		bo->base.ptr = NULL;
176 	}
177 
178 	memset(&arg, 0, sizeof(arg));
179 	arg.handle = bo->base.handle;
180 
181 	ret = drmIoctl(bo->base.kms->fd, DRM_IOCTL_GEM_CLOSE, &arg);
182 	if (ret)
183 		return -errno;
184 
185 	free(bo);
186 	return 0;
187 }
188 
189 drm_private int
exynos_create(int fd,struct kms_driver ** out)190 exynos_create(int fd, struct kms_driver **out)
191 {
192 	struct kms_driver *kms;
193 
194 	kms = calloc(1, sizeof(*kms));
195 	if (!kms)
196 		return -ENOMEM;
197 
198 	kms->fd = fd;
199 
200 	kms->bo_create = exynos_bo_create;
201 	kms->bo_map = exynos_bo_map;
202 	kms->bo_unmap = exynos_bo_unmap;
203 	kms->bo_get_prop = exynos_bo_get_prop;
204 	kms->bo_destroy = exynos_bo_destroy;
205 	kms->get_prop = exynos_get_prop;
206 	kms->destroy = exynos_destroy;
207 	*out = kms;
208 
209 	return 0;
210 }
211