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