Home | History | Annotate | Download | only in libkms
      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