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#include <stdlib.h> 28e88f27b3Smrg#include <stdio.h> 29e88f27b3Smrg#include <string.h> 30e88f27b3Smrg#include <errno.h> 313f012e29Smrg#include <unistd.h> 32e88f27b3Smrg 33e88f27b3Smrg#include <sys/mman.h> 34e88f27b3Smrg 35e88f27b3Smrg#include <xf86drm.h> 36e88f27b3Smrg 37e6188e58Smrg#include "libdrm_macros.h" 38e88f27b3Smrg#include "exynos_drm.h" 39e88f27b3Smrg#include "exynos_drmif.h" 40e88f27b3Smrg 413f012e29Smrg#define U642VOID(x) ((void *)(unsigned long)(x)) 423f012e29Smrg 43e88f27b3Smrg/* 44e88f27b3Smrg * Create exynos drm device object. 45e88f27b3Smrg * 46e88f27b3Smrg * @fd: file descriptor to exynos drm driver opened. 47e88f27b3Smrg * 48e88f27b3Smrg * if true, return the device object else NULL. 49e88f27b3Smrg */ 507cdc0497Smrgdrm_public struct exynos_device * exynos_device_create(int fd) 51e88f27b3Smrg{ 52e88f27b3Smrg struct exynos_device *dev; 53e88f27b3Smrg 54e88f27b3Smrg dev = calloc(sizeof(*dev), 1); 55e88f27b3Smrg if (!dev) { 56e88f27b3Smrg fprintf(stderr, "failed to create device[%s].\n", 57e88f27b3Smrg strerror(errno)); 58e88f27b3Smrg return NULL; 59e88f27b3Smrg } 60e88f27b3Smrg 61e88f27b3Smrg dev->fd = fd; 62e88f27b3Smrg 63e88f27b3Smrg return dev; 64e88f27b3Smrg} 65e88f27b3Smrg 66e88f27b3Smrg/* 67e88f27b3Smrg * Destroy exynos drm device object 68e88f27b3Smrg * 69e88f27b3Smrg * @dev: exynos drm device object. 70e88f27b3Smrg */ 717cdc0497Smrgdrm_public void exynos_device_destroy(struct exynos_device *dev) 72e88f27b3Smrg{ 73e88f27b3Smrg free(dev); 74e88f27b3Smrg} 75e88f27b3Smrg 76e88f27b3Smrg/* 77e88f27b3Smrg * Create a exynos buffer object to exynos drm device. 78e88f27b3Smrg * 79e88f27b3Smrg * @dev: exynos drm device object. 80e88f27b3Smrg * @size: user-desired size. 81e88f27b3Smrg * flags: user-desired memory type. 82e88f27b3Smrg * user can set one or more types among several types to memory 83e88f27b3Smrg * allocation and cache attribute types. and as default, 84e88f27b3Smrg * EXYNOS_BO_NONCONTIG and EXYNOS-BO_NONCACHABLE types would 85e88f27b3Smrg * be used. 86e88f27b3Smrg * 87e88f27b3Smrg * if true, return a exynos buffer object else NULL. 88e88f27b3Smrg */ 897cdc0497Smrgdrm_public struct exynos_bo * exynos_bo_create(struct exynos_device *dev, 907cdc0497Smrg size_t size, uint32_t flags) 91e88f27b3Smrg{ 92e88f27b3Smrg struct exynos_bo *bo; 93e88f27b3Smrg struct drm_exynos_gem_create req = { 94e88f27b3Smrg .size = size, 95e88f27b3Smrg .flags = flags, 96e88f27b3Smrg }; 97e88f27b3Smrg 98e88f27b3Smrg if (size == 0) { 99e88f27b3Smrg fprintf(stderr, "invalid size.\n"); 100e88f27b3Smrg goto fail; 101e88f27b3Smrg } 102e88f27b3Smrg 103e88f27b3Smrg bo = calloc(sizeof(*bo), 1); 104e88f27b3Smrg if (!bo) { 105e88f27b3Smrg fprintf(stderr, "failed to create bo[%s].\n", 106e88f27b3Smrg strerror(errno)); 107e88f27b3Smrg goto err_free_bo; 108e88f27b3Smrg } 109e88f27b3Smrg 110e88f27b3Smrg bo->dev = dev; 111e88f27b3Smrg 112e88f27b3Smrg if (drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_CREATE, &req)){ 113e88f27b3Smrg fprintf(stderr, "failed to create gem object[%s].\n", 114e88f27b3Smrg strerror(errno)); 115e88f27b3Smrg goto err_free_bo; 116e88f27b3Smrg } 117e88f27b3Smrg 118e88f27b3Smrg bo->handle = req.handle; 119e88f27b3Smrg bo->size = size; 120e88f27b3Smrg bo->flags = flags; 121e88f27b3Smrg 122e88f27b3Smrg return bo; 123e88f27b3Smrg 124e88f27b3Smrgerr_free_bo: 125e88f27b3Smrg free(bo); 126e88f27b3Smrgfail: 127e88f27b3Smrg return NULL; 128e88f27b3Smrg} 129e88f27b3Smrg 130e88f27b3Smrg/* 131e88f27b3Smrg * Get information to gem region allocated. 132e88f27b3Smrg * 133e88f27b3Smrg * @dev: exynos drm device object. 134e88f27b3Smrg * @handle: gem handle to request gem info. 135e88f27b3Smrg * @size: size to gem object and returned by kernel side. 136e88f27b3Smrg * @flags: gem flags to gem object and returned by kernel side. 137e88f27b3Smrg * 138e88f27b3Smrg * with this function call, you can get flags and size to gem handle 139e88f27b3Smrg * through bo object. 140e88f27b3Smrg * 141e88f27b3Smrg * if true, return 0 else negative. 142e88f27b3Smrg */ 1437cdc0497Smrgdrm_public int exynos_bo_get_info(struct exynos_device *dev, uint32_t handle, 1447cdc0497Smrg size_t *size, uint32_t *flags) 145e88f27b3Smrg{ 146e88f27b3Smrg int ret; 147e88f27b3Smrg struct drm_exynos_gem_info req = { 148e88f27b3Smrg .handle = handle, 149e88f27b3Smrg }; 150e88f27b3Smrg 151e88f27b3Smrg ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_GET, &req); 152e88f27b3Smrg if (ret < 0) { 153e88f27b3Smrg fprintf(stderr, "failed to get gem object information[%s].\n", 154e88f27b3Smrg strerror(errno)); 155e88f27b3Smrg return ret; 156e88f27b3Smrg } 157e88f27b3Smrg 158e88f27b3Smrg *size = req.size; 159e88f27b3Smrg *flags = req.flags; 160e88f27b3Smrg 161e88f27b3Smrg return 0; 162e88f27b3Smrg} 163e88f27b3Smrg 164e88f27b3Smrg/* 165e88f27b3Smrg * Destroy a exynos buffer object. 166e88f27b3Smrg * 167e88f27b3Smrg * @bo: a exynos buffer object to be destroyed. 168e88f27b3Smrg */ 1697cdc0497Smrgdrm_public void exynos_bo_destroy(struct exynos_bo *bo) 170e88f27b3Smrg{ 171e88f27b3Smrg if (!bo) 172e88f27b3Smrg return; 173e88f27b3Smrg 174e88f27b3Smrg if (bo->vaddr) 175e88f27b3Smrg munmap(bo->vaddr, bo->size); 176e88f27b3Smrg 177e88f27b3Smrg if (bo->handle) { 17849ef06a4Smrg drmCloseBufferHandle(bo->dev->fd, bo->handle); 179e88f27b3Smrg } 180e88f27b3Smrg 181e88f27b3Smrg free(bo); 182e88f27b3Smrg} 183e88f27b3Smrg 184e88f27b3Smrg 185e88f27b3Smrg/* 186e88f27b3Smrg * Get a exynos buffer object from a gem global object name. 187e88f27b3Smrg * 188e88f27b3Smrg * @dev: a exynos device object. 189e88f27b3Smrg * @name: a gem global object name exported by another process. 190e88f27b3Smrg * 191e88f27b3Smrg * this interface is used to get a exynos buffer object from a gem 192e88f27b3Smrg * global object name sent by another process for buffer sharing. 193e88f27b3Smrg * 194e88f27b3Smrg * if true, return a exynos buffer object else NULL. 195e88f27b3Smrg * 196e88f27b3Smrg */ 1977cdc0497Smrgdrm_public struct exynos_bo * 198baaff307Smrgexynos_bo_from_name(struct exynos_device *dev, uint32_t name) 199e88f27b3Smrg{ 200e88f27b3Smrg struct exynos_bo *bo; 201e88f27b3Smrg struct drm_gem_open req = { 202e88f27b3Smrg .name = name, 203e88f27b3Smrg }; 204e88f27b3Smrg 205e88f27b3Smrg bo = calloc(sizeof(*bo), 1); 206e88f27b3Smrg if (!bo) { 207e88f27b3Smrg fprintf(stderr, "failed to allocate bo[%s].\n", 208e88f27b3Smrg strerror(errno)); 209e88f27b3Smrg return NULL; 210e88f27b3Smrg } 211e88f27b3Smrg 212e88f27b3Smrg if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { 213e88f27b3Smrg fprintf(stderr, "failed to open gem object[%s].\n", 214e88f27b3Smrg strerror(errno)); 215e88f27b3Smrg goto err_free_bo; 216e88f27b3Smrg } 217e88f27b3Smrg 218e88f27b3Smrg bo->dev = dev; 219e88f27b3Smrg bo->name = name; 220e88f27b3Smrg bo->handle = req.handle; 221e88f27b3Smrg 222e88f27b3Smrg return bo; 223e88f27b3Smrg 224e88f27b3Smrgerr_free_bo: 225e88f27b3Smrg free(bo); 226e88f27b3Smrg return NULL; 227e88f27b3Smrg} 228e88f27b3Smrg 229e88f27b3Smrg/* 230e88f27b3Smrg * Get a gem global object name from a gem object handle. 231e88f27b3Smrg * 232e88f27b3Smrg * @bo: a exynos buffer object including gem handle. 233e88f27b3Smrg * @name: a gem global object name to be got by kernel driver. 234e88f27b3Smrg * 235e88f27b3Smrg * this interface is used to get a gem global object name from a gem object 236e88f27b3Smrg * handle to a buffer that wants to share it with another process. 237e88f27b3Smrg * 238e88f27b3Smrg * if true, return 0 else negative. 239e88f27b3Smrg */ 2407cdc0497Smrgdrm_public int exynos_bo_get_name(struct exynos_bo *bo, uint32_t *name) 241e88f27b3Smrg{ 242e88f27b3Smrg if (!bo->name) { 243e88f27b3Smrg struct drm_gem_flink req = { 244e88f27b3Smrg .handle = bo->handle, 245e88f27b3Smrg }; 246e88f27b3Smrg int ret; 247e88f27b3Smrg 248e88f27b3Smrg ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req); 249e88f27b3Smrg if (ret) { 250e88f27b3Smrg fprintf(stderr, "failed to get gem global name[%s].\n", 251e88f27b3Smrg strerror(errno)); 252e88f27b3Smrg return ret; 253e88f27b3Smrg } 254e88f27b3Smrg 255e88f27b3Smrg bo->name = req.name; 256e88f27b3Smrg } 257e88f27b3Smrg 258e88f27b3Smrg *name = bo->name; 259e88f27b3Smrg 260e88f27b3Smrg return 0; 261e88f27b3Smrg} 262e88f27b3Smrg 2637cdc0497Smrgdrm_public uint32_t exynos_bo_handle(struct exynos_bo *bo) 264e88f27b3Smrg{ 265e88f27b3Smrg return bo->handle; 266e88f27b3Smrg} 267e88f27b3Smrg 268e88f27b3Smrg/* 269e88f27b3Smrg * Mmap a buffer to user space. 270e88f27b3Smrg * 271e88f27b3Smrg * @bo: a exynos buffer object including a gem object handle to be mmapped 272e88f27b3Smrg * to user space. 273e88f27b3Smrg * 2745324fb0dSmrg * if true, user pointer mmapped else NULL. 275e88f27b3Smrg */ 2767cdc0497Smrgdrm_public void *exynos_bo_map(struct exynos_bo *bo) 277e88f27b3Smrg{ 278e88f27b3Smrg if (!bo->vaddr) { 279e88f27b3Smrg struct exynos_device *dev = bo->dev; 280e6188e58Smrg struct drm_mode_map_dumb arg; 281e6188e58Smrg void *map = NULL; 282e88f27b3Smrg int ret; 283e88f27b3Smrg 284e6188e58Smrg memset(&arg, 0, sizeof(arg)); 285e6188e58Smrg arg.handle = bo->handle; 286e6188e58Smrg 287e6188e58Smrg ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg); 288e88f27b3Smrg if (ret) { 289e6188e58Smrg fprintf(stderr, "failed to map dumb buffer[%s].\n", 290e88f27b3Smrg strerror(errno)); 291e88f27b3Smrg return NULL; 292e88f27b3Smrg } 293e88f27b3Smrg 294e6188e58Smrg map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, 295e6188e58Smrg dev->fd, arg.offset); 296e6188e58Smrg 297e6188e58Smrg if (map != MAP_FAILED) 298e6188e58Smrg bo->vaddr = map; 299e88f27b3Smrg } 300e88f27b3Smrg 301e88f27b3Smrg return bo->vaddr; 302e88f27b3Smrg} 303e88f27b3Smrg 304e88f27b3Smrg/* 305e88f27b3Smrg * Export gem object to dmabuf as file descriptor. 306e88f27b3Smrg * 307baaff307Smrg * @dev: exynos device object 308baaff307Smrg * @handle: gem handle to export as file descriptor of dmabuf 309baaff307Smrg * @fd: file descriptor returned from kernel 310e88f27b3Smrg * 311baaff307Smrg * @return: 0 on success, -1 on error, and errno will be set 312e88f27b3Smrg */ 3137cdc0497Smrgdrm_public int 314baaff307Smrgexynos_prime_handle_to_fd(struct exynos_device *dev, uint32_t handle, int *fd) 315e88f27b3Smrg{ 316baaff307Smrg return drmPrimeHandleToFD(dev->fd, handle, 0, fd); 317e88f27b3Smrg} 318e88f27b3Smrg 319e88f27b3Smrg/* 320e88f27b3Smrg * Import file descriptor into gem handle. 321e88f27b3Smrg * 322baaff307Smrg * @dev: exynos device object 323baaff307Smrg * @fd: file descriptor of dmabuf to import 324baaff307Smrg * @handle: gem handle returned from kernel 325e88f27b3Smrg * 326baaff307Smrg * @return: 0 on success, -1 on error, and errno will be set 327e88f27b3Smrg */ 3287cdc0497Smrgdrm_public int 329baaff307Smrgexynos_prime_fd_to_handle(struct exynos_device *dev, int fd, uint32_t *handle) 330e88f27b3Smrg{ 331baaff307Smrg return drmPrimeFDToHandle(dev->fd, fd, handle); 332e88f27b3Smrg} 333e88f27b3Smrg 334e88f27b3Smrg 335e88f27b3Smrg 336e88f27b3Smrg/* 337e88f27b3Smrg * Request Wireless Display connection or disconnection. 338e88f27b3Smrg * 339e88f27b3Smrg * @dev: a exynos device object. 340e88f27b3Smrg * @connect: indicate whether connectoin or disconnection request. 3413f012e29Smrg * @ext: indicate whether edid data includes extensions data or not. 342e88f27b3Smrg * @edid: a pointer to edid data from Wireless Display device. 343e88f27b3Smrg * 344e88f27b3Smrg * this interface is used to request Virtual Display driver connection or 345e88f27b3Smrg * disconnection. for this, user should get a edid data from the Wireless 346e88f27b3Smrg * Display device and then send that data to kernel driver with connection 347e88f27b3Smrg * request 348e88f27b3Smrg * 349e88f27b3Smrg * if true, return 0 else negative. 350e88f27b3Smrg */ 3517cdc0497Smrgdrm_public int 352baaff307Smrgexynos_vidi_connection(struct exynos_device *dev, uint32_t connect, 353baaff307Smrg uint32_t ext, void *edid) 354e88f27b3Smrg{ 355e88f27b3Smrg struct drm_exynos_vidi_connection req = { 356e88f27b3Smrg .connection = connect, 357e88f27b3Smrg .extensions = ext, 358baaff307Smrg .edid = (uint64_t)(uintptr_t)edid, 359e88f27b3Smrg }; 360e88f27b3Smrg int ret; 361e88f27b3Smrg 362e88f27b3Smrg ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_VIDI_CONNECTION, &req); 363e88f27b3Smrg if (ret) { 364e88f27b3Smrg fprintf(stderr, "failed to request vidi connection[%s].\n", 365e88f27b3Smrg strerror(errno)); 366e88f27b3Smrg return ret; 367e88f27b3Smrg } 368e88f27b3Smrg 369e88f27b3Smrg return 0; 370e88f27b3Smrg} 3713f012e29Smrg 3723f012e29Smrgstatic void 3733f012e29Smrgexynos_handle_vendor(int fd, struct drm_event *e, void *ctx) 3743f012e29Smrg{ 3753f012e29Smrg struct drm_exynos_g2d_event *g2d; 3763f012e29Smrg struct exynos_event_context *ectx = ctx; 3773f012e29Smrg 3783f012e29Smrg switch (e->type) { 3793f012e29Smrg case DRM_EXYNOS_G2D_EVENT: 3803f012e29Smrg if (ectx->version < 1 || ectx->g2d_event_handler == NULL) 3813f012e29Smrg break; 3823f012e29Smrg g2d = (struct drm_exynos_g2d_event *)e; 3833f012e29Smrg ectx->g2d_event_handler(fd, g2d->cmdlist_no, g2d->tv_sec, 3843f012e29Smrg g2d->tv_usec, U642VOID(g2d->user_data)); 3853f012e29Smrg break; 3863f012e29Smrg 3873f012e29Smrg default: 3883f012e29Smrg break; 3893f012e29Smrg } 3903f012e29Smrg} 3913f012e29Smrg 3927cdc0497Smrgdrm_public int 3933f012e29Smrgexynos_handle_event(struct exynos_device *dev, struct exynos_event_context *ctx) 3943f012e29Smrg{ 3953f012e29Smrg char buffer[1024]; 3963f012e29Smrg int len, i; 3973f012e29Smrg struct drm_event *e; 3983f012e29Smrg struct drm_event_vblank *vblank; 3993f012e29Smrg drmEventContextPtr evctx = &ctx->base; 4003f012e29Smrg 4013f012e29Smrg /* The DRM read semantics guarantees that we always get only 4023f012e29Smrg * complete events. */ 4033f012e29Smrg len = read(dev->fd, buffer, sizeof buffer); 4043f012e29Smrg if (len == 0) 4053f012e29Smrg return 0; 4063f012e29Smrg if (len < (int)sizeof *e) 4073f012e29Smrg return -1; 4083f012e29Smrg 4093f012e29Smrg i = 0; 4103f012e29Smrg while (i < len) { 411d8807b2fSmrg e = (struct drm_event *)(buffer + i); 4123f012e29Smrg switch (e->type) { 4133f012e29Smrg case DRM_EVENT_VBLANK: 4143f012e29Smrg if (evctx->version < 1 || 4153f012e29Smrg evctx->vblank_handler == NULL) 4163f012e29Smrg break; 4173f012e29Smrg vblank = (struct drm_event_vblank *) e; 4183f012e29Smrg evctx->vblank_handler(dev->fd, 4193f012e29Smrg vblank->sequence, 4203f012e29Smrg vblank->tv_sec, 4213f012e29Smrg vblank->tv_usec, 4223f012e29Smrg U642VOID (vblank->user_data)); 4233f012e29Smrg break; 4243f012e29Smrg case DRM_EVENT_FLIP_COMPLETE: 4253f012e29Smrg if (evctx->version < 2 || 4263f012e29Smrg evctx->page_flip_handler == NULL) 4273f012e29Smrg break; 4283f012e29Smrg vblank = (struct drm_event_vblank *) e; 4293f012e29Smrg evctx->page_flip_handler(dev->fd, 4303f012e29Smrg vblank->sequence, 4313f012e29Smrg vblank->tv_sec, 4323f012e29Smrg vblank->tv_usec, 4333f012e29Smrg U642VOID (vblank->user_data)); 4343f012e29Smrg break; 4353f012e29Smrg default: 4363f012e29Smrg exynos_handle_vendor(dev->fd, e, evctx); 4373f012e29Smrg break; 4383f012e29Smrg } 4393f012e29Smrg i += e->length; 4403f012e29Smrg } 4413f012e29Smrg 4423f012e29Smrg return 0; 4433f012e29Smrg} 444