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 "exynos_drm.h" 29 30 struct exynos_bo 31 { 32 struct kms_bo base; 33 unsigned map_count; 34 }; 35 36 static int 37 exynos_get_prop(struct kms_driver *kms, unsigned key, unsigned *out) 38 { 39 switch (key) { 40 case KMS_BO_TYPE: 41 *out = KMS_BO_TYPE_SCANOUT_X8R8G8B8 | KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8; 42 break; 43 default: 44 return -EINVAL; 45 } 46 return 0; 47 } 48 49 static int 50 exynos_destroy(struct kms_driver *kms) 51 { 52 free(kms); 53 return 0; 54 } 55 56 static int 57 exynos_bo_create(struct kms_driver *kms, 58 const unsigned width, const unsigned height, 59 const enum kms_bo_type type, const unsigned *attr, 60 struct kms_bo **out) 61 { 62 struct drm_exynos_gem_create arg; 63 unsigned size, pitch; 64 struct exynos_bo *bo; 65 int i, ret; 66 67 for (i = 0; attr[i]; i += 2) { 68 switch (attr[i]) { 69 case KMS_WIDTH: 70 case KMS_HEIGHT: 71 case KMS_BO_TYPE: 72 break; 73 default: 74 return -EINVAL; 75 } 76 } 77 78 bo = calloc(1, sizeof(*bo)); 79 if (!bo) 80 return -ENOMEM; 81 82 if (type == KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8) { 83 pitch = 64 * 4; 84 size = 64 * 64 * 4; 85 } else if (type == KMS_BO_TYPE_SCANOUT_X8R8G8B8) { 86 pitch = width * 4; 87 pitch = (pitch + 512 - 1) & ~(512 - 1); 88 size = pitch * ((height + 4 - 1) & ~(4 - 1)); 89 } else { 90 return -EINVAL; 91 } 92 93 memset(&arg, 0, sizeof(arg)); 94 arg.size = size; 95 96 ret = drmCommandWriteRead(kms->fd, DRM_EXYNOS_GEM_CREATE, &arg, sizeof(arg)); 97 if (ret) 98 goto err_free; 99 100 bo->base.kms = kms; 101 bo->base.handle = arg.handle; 102 bo->base.size = size; 103 bo->base.pitch = pitch; 104 105 *out = &bo->base; 106 107 return 0; 108 109 err_free: 110 free(bo); 111 return ret; 112 } 113 114 static int 115 exynos_bo_get_prop(struct kms_bo *bo, unsigned key, unsigned *out) 116 { 117 switch (key) { 118 default: 119 return -EINVAL; 120 } 121 } 122 123 static int 124 exynos_bo_map(struct kms_bo *_bo, void **out) 125 { 126 struct exynos_bo *bo = (struct exynos_bo *)_bo; 127 struct drm_exynos_gem_map_off arg; 128 void *map = NULL; 129 int ret; 130 131 if (bo->base.ptr) { 132 bo->map_count++; 133 *out = bo->base.ptr; 134 return 0; 135 } 136 137 memset(&arg, 0, sizeof(arg)); 138 arg.handle = bo->base.handle; 139 140 ret = drmCommandWriteRead(bo->base.kms->fd, DRM_EXYNOS_GEM_MAP_OFFSET, &arg, sizeof(arg)); 141 if (ret) 142 return ret; 143 144 map = mmap(0, bo->base.size, PROT_READ | PROT_WRITE, MAP_SHARED, bo->base.kms->fd, arg.offset); 145 if (map == MAP_FAILED) 146 return -errno; 147 148 bo->base.ptr = map; 149 bo->map_count++; 150 *out = bo->base.ptr; 151 152 return 0; 153 } 154 155 static int 156 exynos_bo_unmap(struct kms_bo *_bo) 157 { 158 struct exynos_bo *bo = (struct exynos_bo *)_bo; 159 bo->map_count--; 160 return 0; 161 } 162 163 static int 164 exynos_bo_destroy(struct kms_bo *_bo) 165 { 166 struct exynos_bo *bo = (struct exynos_bo *)_bo; 167 struct drm_gem_close arg; 168 int ret; 169 170 if (bo->base.ptr) { 171 /* XXX Sanity check map_count */ 172 munmap(bo->base.ptr, bo->base.size); 173 bo->base.ptr = NULL; 174 } 175 176 memset(&arg, 0, sizeof(arg)); 177 arg.handle = bo->base.handle; 178 179 ret = drmIoctl(bo->base.kms->fd, DRM_IOCTL_GEM_CLOSE, &arg); 180 if (ret) 181 return -errno; 182 183 free(bo); 184 return 0; 185 } 186 187 int 188 exynos_create(int fd, struct kms_driver **out) 189 { 190 struct kms_driver *kms; 191 192 kms = calloc(1, sizeof(*kms)); 193 if (!kms) 194 return -ENOMEM; 195 196 kms->fd = fd; 197 198 kms->bo_create = exynos_bo_create; 199 kms->bo_map = exynos_bo_map; 200 kms->bo_unmap = exynos_bo_unmap; 201 kms->bo_get_prop = exynos_bo_get_prop; 202 kms->bo_destroy = exynos_bo_destroy; 203 kms->get_prop = exynos_get_prop; 204 kms->destroy = exynos_destroy; 205 *out = kms; 206 207 return 0; 208 } 209