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 "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