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