1 /* exynos.c 2 * 3 * Copyright 2009 Samsung Electronics Co., Ltd. 4 * Authors: 5 * SooChan Lim <sc1.lim (at) samsung.com> 6 * Sangjin LEE <lsj119 (at) 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 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 51 exynos_destroy(struct kms_driver *kms) 52 { 53 free(kms); 54 return 0; 55 } 56 57 static int 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 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 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 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 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 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