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