Home | History | Annotate | Download | only in tegra
      1 /*
      2  * Copyright  2012, 2013 Thierry Reding
      3  * Copyright  2013 Erik Faye-Lund
      4  * Copyright  2014 NVIDIA Corporation
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 #ifdef HAVE_CONFIG_H
     26 #  include "config.h"
     27 #endif
     28 
     29 #include <errno.h>
     30 #include <fcntl.h>
     31 #include <string.h>
     32 #include <unistd.h>
     33 
     34 #include <sys/mman.h>
     35 
     36 #include <xf86drm.h>
     37 
     38 #include <tegra_drm.h>
     39 
     40 #include "private.h"
     41 
     42 static void drm_tegra_bo_free(struct drm_tegra_bo *bo)
     43 {
     44 	struct drm_tegra *drm = bo->drm;
     45 	struct drm_gem_close args;
     46 
     47 	if (bo->map)
     48 		munmap(bo->map, bo->size);
     49 
     50 	memset(&args, 0, sizeof(args));
     51 	args.handle = bo->handle;
     52 
     53 	drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &args);
     54 
     55 	free(bo);
     56 }
     57 
     58 static int drm_tegra_wrap(struct drm_tegra **drmp, int fd, bool close)
     59 {
     60 	struct drm_tegra *drm;
     61 
     62 	if (fd < 0 || !drmp)
     63 		return -EINVAL;
     64 
     65 	drm = calloc(1, sizeof(*drm));
     66 	if (!drm)
     67 		return -ENOMEM;
     68 
     69 	drm->close = close;
     70 	drm->fd = fd;
     71 
     72 	*drmp = drm;
     73 
     74 	return 0;
     75 }
     76 
     77 drm_public
     78 int drm_tegra_new(struct drm_tegra **drmp, int fd)
     79 {
     80 	bool supported = false;
     81 	drmVersionPtr version;
     82 
     83 	version = drmGetVersion(fd);
     84 	if (!version)
     85 		return -ENOMEM;
     86 
     87 	if (!strncmp(version->name, "tegra", version->name_len))
     88 		supported = true;
     89 
     90 	drmFreeVersion(version);
     91 
     92 	if (!supported)
     93 		return -ENOTSUP;
     94 
     95 	return drm_tegra_wrap(drmp, fd, false);
     96 }
     97 
     98 drm_public
     99 void drm_tegra_close(struct drm_tegra *drm)
    100 {
    101 	if (!drm)
    102 		return;
    103 
    104 	if (drm->close)
    105 		close(drm->fd);
    106 
    107 	free(drm);
    108 }
    109 
    110 drm_public
    111 int drm_tegra_bo_new(struct drm_tegra_bo **bop, struct drm_tegra *drm,
    112 		     uint32_t flags, uint32_t size)
    113 {
    114 	struct drm_tegra_gem_create args;
    115 	struct drm_tegra_bo *bo;
    116 	int err;
    117 
    118 	if (!drm || size == 0 || !bop)
    119 		return -EINVAL;
    120 
    121 	bo = calloc(1, sizeof(*bo));
    122 	if (!bo)
    123 		return -ENOMEM;
    124 
    125 	atomic_set(&bo->ref, 1);
    126 	bo->flags = flags;
    127 	bo->size = size;
    128 	bo->drm = drm;
    129 
    130 	memset(&args, 0, sizeof(args));
    131 	args.flags = flags;
    132 	args.size = size;
    133 
    134 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_CREATE, &args,
    135 				  sizeof(args));
    136 	if (err < 0) {
    137 		err = -errno;
    138 		free(bo);
    139 		return err;
    140 	}
    141 
    142 	bo->handle = args.handle;
    143 
    144 	*bop = bo;
    145 
    146 	return 0;
    147 }
    148 
    149 drm_public
    150 int drm_tegra_bo_wrap(struct drm_tegra_bo **bop, struct drm_tegra *drm,
    151 		      uint32_t handle, uint32_t flags, uint32_t size)
    152 {
    153 	struct drm_tegra_bo *bo;
    154 
    155 	if (!drm || !bop)
    156 		return -EINVAL;
    157 
    158 	bo = calloc(1, sizeof(*bo));
    159 	if (!bo)
    160 		return -ENOMEM;
    161 
    162 	atomic_set(&bo->ref, 1);
    163 	bo->handle = handle;
    164 	bo->flags = flags;
    165 	bo->size = size;
    166 	bo->drm = drm;
    167 
    168 	*bop = bo;
    169 
    170 	return 0;
    171 }
    172 
    173 drm_public
    174 int drm_tegra_bo_name_ref(struct drm_tegra *drm, uint32_t name, uint32_t size,
    175 			 struct drm_tegra_bo **bop)
    176 {
    177 	struct drm_tegra_bo *bo;
    178 	struct drm_gem_open open_args;
    179 	struct drm_gem_close close_args;
    180 	int ret;
    181 
    182 	memset(&open_args, 0, sizeof(open_args));
    183 
    184 	open_args.name = name;
    185 
    186 	ret = drmIoctl(drm->fd, DRM_IOCTL_GEM_OPEN, &open_args);
    187 	if (ret)
    188 		return ret;
    189 
    190 	ret = drm_tegra_bo_wrap(bop, drm, open_args.handle, 0, size);
    191 	if (ret)
    192 		goto err;
    193 
    194 	(*bop)->name = name;
    195 
    196 	return 0;
    197 
    198 err:
    199 	memset(&close_args, 0, sizeof(close_args));
    200 	close_args.handle = open_args.handle;
    201 	drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &close_args);
    202 
    203 	return ret;
    204 }
    205 
    206 drm_public
    207 int drm_tegra_bo_name_get(struct drm_tegra_bo *bo, uint32_t *name)
    208 {
    209 	struct drm_gem_flink args;
    210 	int ret;
    211 
    212 	args.handle =  bo->handle;
    213 
    214 	*name = bo->name;
    215 	if (*name && *name != ~0U)
    216 		return 0;
    217 
    218 	ret = drmIoctl(bo->drm->fd, DRM_IOCTL_GEM_FLINK, &args);
    219 	if (ret) {
    220 		*name = 0;
    221 		return ret;
    222 	}
    223 
    224 	bo->name = args.name;
    225 	*name = bo->name;
    226 
    227 	return 0;
    228 }
    229 
    230 drm_public
    231 struct drm_tegra_bo *drm_tegra_bo_ref(struct drm_tegra_bo *bo)
    232 {
    233 	if (bo)
    234 		atomic_inc(&bo->ref);
    235 
    236 	return bo;
    237 }
    238 
    239 drm_public
    240 void drm_tegra_bo_unref(struct drm_tegra_bo *bo)
    241 {
    242 	if (bo && atomic_dec_and_test(&bo->ref))
    243 		drm_tegra_bo_free(bo);
    244 }
    245 
    246 drm_public
    247 int drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle)
    248 {
    249 	if (!bo || !handle)
    250 		return -EINVAL;
    251 
    252 	*handle = bo->handle;
    253 
    254 	return 0;
    255 }
    256 
    257 drm_public
    258 int drm_tegra_bo_map(struct drm_tegra_bo *bo, void **ptr)
    259 {
    260 	struct drm_tegra *drm = bo->drm;
    261 
    262 	if (!bo->map) {
    263 		struct drm_tegra_gem_mmap args;
    264 		int err;
    265 
    266 		memset(&args, 0, sizeof(args));
    267 		args.handle = bo->handle;
    268 
    269 		err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_MMAP, &args,
    270 					  sizeof(args));
    271 		if (err < 0)
    272 			return -errno;
    273 
    274 		bo->offset = args.offset;
    275 
    276 		bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
    277 			       drm->fd, bo->offset);
    278 		if (bo->map == MAP_FAILED) {
    279 			bo->map = NULL;
    280 			return -errno;
    281 		}
    282 	}
    283 
    284 	if (ptr)
    285 		*ptr = bo->map;
    286 
    287 	return 0;
    288 }
    289 
    290 drm_public
    291 int drm_tegra_bo_unmap(struct drm_tegra_bo *bo)
    292 {
    293 	if (!bo)
    294 		return -EINVAL;
    295 
    296 	if (!bo->map)
    297 		return 0;
    298 
    299 	if (munmap(bo->map, bo->size))
    300 		return -errno;
    301 
    302 	bo->map = NULL;
    303 
    304 	return 0;
    305 }
    306 
    307 drm_public
    308 int drm_tegra_bo_get_flags(struct drm_tegra_bo *bo, uint32_t *flags)
    309 {
    310 	struct drm_tegra_gem_get_flags args;
    311 	struct drm_tegra *drm = bo->drm;
    312 	int err;
    313 
    314 	if (!bo)
    315 		return -EINVAL;
    316 
    317 	memset(&args, 0, sizeof(args));
    318 	args.handle = bo->handle;
    319 
    320 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_FLAGS, &args,
    321 				  sizeof(args));
    322 	if (err < 0)
    323 		return -errno;
    324 
    325 	if (flags)
    326 		*flags = args.flags;
    327 
    328 	return 0;
    329 }
    330 
    331 drm_public
    332 int drm_tegra_bo_set_flags(struct drm_tegra_bo *bo, uint32_t flags)
    333 {
    334 	struct drm_tegra_gem_get_flags args;
    335 	struct drm_tegra *drm = bo->drm;
    336 	int err;
    337 
    338 	if (!bo)
    339 		return -EINVAL;
    340 
    341 	memset(&args, 0, sizeof(args));
    342 	args.handle = bo->handle;
    343 	args.flags = flags;
    344 
    345 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_FLAGS, &args,
    346 				  sizeof(args));
    347 	if (err < 0)
    348 		return -errno;
    349 
    350 	return 0;
    351 }
    352 
    353 drm_public
    354 int drm_tegra_bo_get_tiling(struct drm_tegra_bo *bo,
    355 			    struct drm_tegra_bo_tiling *tiling)
    356 {
    357 	struct drm_tegra_gem_get_tiling args;
    358 	struct drm_tegra *drm = bo->drm;
    359 	int err;
    360 
    361 	if (!bo)
    362 		return -EINVAL;
    363 
    364 	memset(&args, 0, sizeof(args));
    365 	args.handle = bo->handle;
    366 
    367 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_TILING, &args,
    368 				  sizeof(args));
    369 	if (err < 0)
    370 		return -errno;
    371 
    372 	if (tiling) {
    373 		tiling->mode = args.mode;
    374 		tiling->value = args.value;
    375 	}
    376 
    377 	return 0;
    378 }
    379 
    380 drm_public
    381 int drm_tegra_bo_set_tiling(struct drm_tegra_bo *bo,
    382 			    const struct drm_tegra_bo_tiling *tiling)
    383 {
    384 	struct drm_tegra_gem_set_tiling args;
    385 	struct drm_tegra *drm = bo->drm;
    386 	int err;
    387 
    388 	if (!bo)
    389 		return -EINVAL;
    390 
    391 	memset(&args, 0, sizeof(args));
    392 	args.handle = bo->handle;
    393 	args.mode = tiling->mode;
    394 	args.value = tiling->value;
    395 
    396 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_TILING, &args,
    397 				  sizeof(args));
    398 	if (err < 0)
    399 		return -errno;
    400 
    401 	return 0;
    402 }
    403