Home | History | Annotate | Download | only in exynos
      1 /*
      2  * Copyright (C) 2012 Samsung Electronics Co., Ltd.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     21  * SOFTWARE.
     22  *
     23  * Authors:
     24  *    Inki Dae <inki.dae (at) samsung.com>
     25  */
     26 
     27 #ifdef HAVE_CONFIG_H
     28 #include "config.h"
     29 #endif
     30 
     31 #include <stdlib.h>
     32 #include <stdio.h>
     33 #include <string.h>
     34 #include <errno.h>
     35 #include <unistd.h>
     36 
     37 #include <sys/mman.h>
     38 #include <linux/stddef.h>
     39 
     40 #include <xf86drm.h>
     41 
     42 #include "libdrm_macros.h"
     43 #include "exynos_drm.h"
     44 #include "exynos_drmif.h"
     45 
     46 #define U642VOID(x) ((void *)(unsigned long)(x))
     47 
     48 /*
     49  * Create exynos drm device object.
     50  *
     51  * @fd: file descriptor to exynos drm driver opened.
     52  *
     53  * if true, return the device object else NULL.
     54  */
     55 struct exynos_device * exynos_device_create(int fd)
     56 {
     57 	struct exynos_device *dev;
     58 
     59 	dev = calloc(sizeof(*dev), 1);
     60 	if (!dev) {
     61 		fprintf(stderr, "failed to create device[%s].\n",
     62 				strerror(errno));
     63 		return NULL;
     64 	}
     65 
     66 	dev->fd = fd;
     67 
     68 	return dev;
     69 }
     70 
     71 /*
     72  * Destroy exynos drm device object
     73  *
     74  * @dev: exynos drm device object.
     75  */
     76 void exynos_device_destroy(struct exynos_device *dev)
     77 {
     78 	free(dev);
     79 }
     80 
     81 /*
     82  * Create a exynos buffer object to exynos drm device.
     83  *
     84  * @dev: exynos drm device object.
     85  * @size: user-desired size.
     86  * flags: user-desired memory type.
     87  *	user can set one or more types among several types to memory
     88  *	allocation and cache attribute types. and as default,
     89  *	EXYNOS_BO_NONCONTIG and EXYNOS-BO_NONCACHABLE types would
     90  *	be used.
     91  *
     92  * if true, return a exynos buffer object else NULL.
     93  */
     94 struct exynos_bo * exynos_bo_create(struct exynos_device *dev,
     95 					       size_t size, uint32_t flags)
     96 {
     97 	struct exynos_bo *bo;
     98 	struct drm_exynos_gem_create req = {
     99 		.size = size,
    100 		.flags = flags,
    101 	};
    102 
    103 	if (size == 0) {
    104 		fprintf(stderr, "invalid size.\n");
    105 		goto fail;
    106 	}
    107 
    108 	bo = calloc(sizeof(*bo), 1);
    109 	if (!bo) {
    110 		fprintf(stderr, "failed to create bo[%s].\n",
    111 				strerror(errno));
    112 		goto err_free_bo;
    113 	}
    114 
    115 	bo->dev = dev;
    116 
    117 	if (drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_CREATE, &req)){
    118 		fprintf(stderr, "failed to create gem object[%s].\n",
    119 				strerror(errno));
    120 		goto err_free_bo;
    121 	}
    122 
    123 	bo->handle = req.handle;
    124 	bo->size = size;
    125 	bo->flags = flags;
    126 
    127 	return bo;
    128 
    129 err_free_bo:
    130 	free(bo);
    131 fail:
    132 	return NULL;
    133 }
    134 
    135 /*
    136  * Get information to gem region allocated.
    137  *
    138  * @dev: exynos drm device object.
    139  * @handle: gem handle to request gem info.
    140  * @size: size to gem object and returned by kernel side.
    141  * @flags: gem flags to gem object and returned by kernel side.
    142  *
    143  * with this function call, you can get flags and size to gem handle
    144  * through bo object.
    145  *
    146  * if true, return 0 else negative.
    147  */
    148 int exynos_bo_get_info(struct exynos_device *dev, uint32_t handle,
    149 				  size_t *size, uint32_t *flags)
    150 {
    151 	int ret;
    152 	struct drm_exynos_gem_info req = {
    153 		.handle = handle,
    154 	};
    155 
    156 	ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_GET, &req);
    157 	if (ret < 0) {
    158 		fprintf(stderr, "failed to get gem object information[%s].\n",
    159 				strerror(errno));
    160 		return ret;
    161 	}
    162 
    163 	*size = req.size;
    164 	*flags = req.flags;
    165 
    166 	return 0;
    167 }
    168 
    169 /*
    170  * Destroy a exynos buffer object.
    171  *
    172  * @bo: a exynos buffer object to be destroyed.
    173  */
    174 void exynos_bo_destroy(struct exynos_bo *bo)
    175 {
    176 	if (!bo)
    177 		return;
    178 
    179 	if (bo->vaddr)
    180 		munmap(bo->vaddr, bo->size);
    181 
    182 	if (bo->handle) {
    183 		struct drm_gem_close req = {
    184 			.handle = bo->handle,
    185 		};
    186 
    187 		drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
    188 	}
    189 
    190 	free(bo);
    191 }
    192 
    193 
    194 /*
    195  * Get a exynos buffer object from a gem global object name.
    196  *
    197  * @dev: a exynos device object.
    198  * @name: a gem global object name exported by another process.
    199  *
    200  * this interface is used to get a exynos buffer object from a gem
    201  * global object name sent by another process for buffer sharing.
    202  *
    203  * if true, return a exynos buffer object else NULL.
    204  *
    205  */
    206 struct exynos_bo *
    207 exynos_bo_from_name(struct exynos_device *dev, uint32_t name)
    208 {
    209 	struct exynos_bo *bo;
    210 	struct drm_gem_open req = {
    211 		.name = name,
    212 	};
    213 
    214 	bo = calloc(sizeof(*bo), 1);
    215 	if (!bo) {
    216 		fprintf(stderr, "failed to allocate bo[%s].\n",
    217 				strerror(errno));
    218 		return NULL;
    219 	}
    220 
    221 	if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) {
    222 		fprintf(stderr, "failed to open gem object[%s].\n",
    223 				strerror(errno));
    224 		goto err_free_bo;
    225 	}
    226 
    227 	bo->dev = dev;
    228 	bo->name = name;
    229 	bo->handle = req.handle;
    230 
    231 	return bo;
    232 
    233 err_free_bo:
    234 	free(bo);
    235 	return NULL;
    236 }
    237 
    238 /*
    239  * Get a gem global object name from a gem object handle.
    240  *
    241  * @bo: a exynos buffer object including gem handle.
    242  * @name: a gem global object name to be got by kernel driver.
    243  *
    244  * this interface is used to get a gem global object name from a gem object
    245  * handle to a buffer that wants to share it with another process.
    246  *
    247  * if true, return 0 else negative.
    248  */
    249 int exynos_bo_get_name(struct exynos_bo *bo, uint32_t *name)
    250 {
    251 	if (!bo->name) {
    252 		struct drm_gem_flink req = {
    253 			.handle = bo->handle,
    254 		};
    255 		int ret;
    256 
    257 		ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
    258 		if (ret) {
    259 			fprintf(stderr, "failed to get gem global name[%s].\n",
    260 					strerror(errno));
    261 			return ret;
    262 		}
    263 
    264 		bo->name = req.name;
    265 	}
    266 
    267 	*name = bo->name;
    268 
    269 	return 0;
    270 }
    271 
    272 uint32_t exynos_bo_handle(struct exynos_bo *bo)
    273 {
    274 	return bo->handle;
    275 }
    276 
    277 /*
    278  * Mmap a buffer to user space.
    279  *
    280  * @bo: a exynos buffer object including a gem object handle to be mmapped
    281  *	to user space.
    282  *
    283  * if true, user pointer mmaped else NULL.
    284  */
    285 void *exynos_bo_map(struct exynos_bo *bo)
    286 {
    287 	if (!bo->vaddr) {
    288 		struct exynos_device *dev = bo->dev;
    289 		struct drm_mode_map_dumb arg;
    290 		void *map = NULL;
    291 		int ret;
    292 
    293 		memset(&arg, 0, sizeof(arg));
    294 		arg.handle = bo->handle;
    295 
    296 		ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
    297 		if (ret) {
    298 			fprintf(stderr, "failed to map dumb buffer[%s].\n",
    299 				strerror(errno));
    300 			return NULL;
    301 		}
    302 
    303 		map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
    304 				dev->fd, arg.offset);
    305 
    306 		if (map != MAP_FAILED)
    307 			bo->vaddr = map;
    308 	}
    309 
    310 	return bo->vaddr;
    311 }
    312 
    313 /*
    314  * Export gem object to dmabuf as file descriptor.
    315  *
    316  * @dev: exynos device object
    317  * @handle: gem handle to export as file descriptor of dmabuf
    318  * @fd: file descriptor returned from kernel
    319  *
    320  * @return: 0 on success, -1 on error, and errno will be set
    321  */
    322 int
    323 exynos_prime_handle_to_fd(struct exynos_device *dev, uint32_t handle, int *fd)
    324 {
    325 	return drmPrimeHandleToFD(dev->fd, handle, 0, fd);
    326 }
    327 
    328 /*
    329  * Import file descriptor into gem handle.
    330  *
    331  * @dev: exynos device object
    332  * @fd: file descriptor of dmabuf to import
    333  * @handle: gem handle returned from kernel
    334  *
    335  * @return: 0 on success, -1 on error, and errno will be set
    336  */
    337 int
    338 exynos_prime_fd_to_handle(struct exynos_device *dev, int fd, uint32_t *handle)
    339 {
    340 	return drmPrimeFDToHandle(dev->fd, fd, handle);
    341 }
    342 
    343 
    344 
    345 /*
    346  * Request Wireless Display connection or disconnection.
    347  *
    348  * @dev: a exynos device object.
    349  * @connect: indicate whether connectoin or disconnection request.
    350  * @ext: indicate whether edid data includes extensions data or not.
    351  * @edid: a pointer to edid data from Wireless Display device.
    352  *
    353  * this interface is used to request Virtual Display driver connection or
    354  * disconnection. for this, user should get a edid data from the Wireless
    355  * Display device and then send that data to kernel driver with connection
    356  * request
    357  *
    358  * if true, return 0 else negative.
    359  */
    360 int
    361 exynos_vidi_connection(struct exynos_device *dev, uint32_t connect,
    362 		       uint32_t ext, void *edid)
    363 {
    364 	struct drm_exynos_vidi_connection req = {
    365 		.connection	= connect,
    366 		.extensions	= ext,
    367 		.edid		= (uint64_t)(uintptr_t)edid,
    368 	};
    369 	int ret;
    370 
    371 	ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_VIDI_CONNECTION, &req);
    372 	if (ret) {
    373 		fprintf(stderr, "failed to request vidi connection[%s].\n",
    374 				strerror(errno));
    375 		return ret;
    376 	}
    377 
    378 	return 0;
    379 }
    380 
    381 static void
    382 exynos_handle_vendor(int fd, struct drm_event *e, void *ctx)
    383 {
    384 	struct drm_exynos_g2d_event *g2d;
    385 	struct exynos_event_context *ectx = ctx;
    386 
    387 	switch (e->type) {
    388 		case DRM_EXYNOS_G2D_EVENT:
    389 			if (ectx->version < 1 || ectx->g2d_event_handler == NULL)
    390 				break;
    391 			g2d = (struct drm_exynos_g2d_event *)e;
    392 			ectx->g2d_event_handler(fd, g2d->cmdlist_no, g2d->tv_sec,
    393 						g2d->tv_usec, U642VOID(g2d->user_data));
    394 			break;
    395 
    396 		default:
    397 			break;
    398 	}
    399 }
    400 
    401 int
    402 exynos_handle_event(struct exynos_device *dev, struct exynos_event_context *ctx)
    403 {
    404 	char buffer[1024];
    405 	int len, i;
    406 	struct drm_event *e;
    407 	struct drm_event_vblank *vblank;
    408 	drmEventContextPtr evctx = &ctx->base;
    409 
    410 	/* The DRM read semantics guarantees that we always get only
    411 	 * complete events. */
    412 	len = read(dev->fd, buffer, sizeof buffer);
    413 	if (len == 0)
    414 		return 0;
    415 	if (len < (int)sizeof *e)
    416 		return -1;
    417 
    418 	i = 0;
    419 	while (i < len) {
    420 		e = (struct drm_event *) &buffer[i];
    421 		switch (e->type) {
    422 		case DRM_EVENT_VBLANK:
    423 			if (evctx->version < 1 ||
    424 			    evctx->vblank_handler == NULL)
    425 				break;
    426 			vblank = (struct drm_event_vblank *) e;
    427 			evctx->vblank_handler(dev->fd,
    428 					      vblank->sequence,
    429 					      vblank->tv_sec,
    430 					      vblank->tv_usec,
    431 					      U642VOID (vblank->user_data));
    432 			break;
    433 		case DRM_EVENT_FLIP_COMPLETE:
    434 			if (evctx->version < 2 ||
    435 			    evctx->page_flip_handler == NULL)
    436 				break;
    437 			vblank = (struct drm_event_vblank *) e;
    438 			evctx->page_flip_handler(dev->fd,
    439 						 vblank->sequence,
    440 						 vblank->tv_sec,
    441 						 vblank->tv_usec,
    442 						 U642VOID (vblank->user_data));
    443 			break;
    444 		default:
    445 			exynos_handle_vendor(dev->fd, e, evctx);
    446 			break;
    447 		}
    448 		i += e->length;
    449 	}
    450 
    451 	return 0;
    452 }
    453