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 #include <errno.h>
     26 #include <fcntl.h>
     27 #include <string.h>
     28 #include <unistd.h>
     29 
     30 #include <sys/mman.h>
     31 
     32 #include <xf86drm.h>
     33 
     34 #include <tegra_drm.h>
     35 
     36 #include "private.h"
     37 
     38 static void drm_tegra_bo_free(struct drm_tegra_bo *bo)
     39 {
     40 	struct drm_tegra *drm = bo->drm;
     41 	struct drm_gem_close args;
     42 
     43 	if (bo->map)
     44 		munmap(bo->map, bo->size);
     45 
     46 	memset(&args, 0, sizeof(args));
     47 	args.handle = bo->handle;
     48 
     49 	drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &args);
     50 
     51 	free(bo);
     52 }
     53 
     54 static int drm_tegra_wrap(struct drm_tegra **drmp, int fd, bool close)
     55 {
     56 	struct drm_tegra *drm;
     57 
     58 	if (fd < 0 || !drmp)
     59 		return -EINVAL;
     60 
     61 	drm = calloc(1, sizeof(*drm));
     62 	if (!drm)
     63 		return -ENOMEM;
     64 
     65 	drm->close = close;
     66 	drm->fd = fd;
     67 
     68 	*drmp = drm;
     69 
     70 	return 0;
     71 }
     72 
     73 int drm_tegra_new(struct drm_tegra **drmp, int fd)
     74 {
     75 	bool supported = false;
     76 	drmVersionPtr version;
     77 
     78 	version = drmGetVersion(fd);
     79 	if (!version)
     80 		return -ENOMEM;
     81 
     82 	if (!strncmp(version->name, "tegra", version->name_len))
     83 		supported = true;
     84 
     85 	drmFreeVersion(version);
     86 
     87 	if (!supported)
     88 		return -ENOTSUP;
     89 
     90 	return drm_tegra_wrap(drmp, fd, false);
     91 }
     92 
     93 void drm_tegra_close(struct drm_tegra *drm)
     94 {
     95 	if (!drm)
     96 		return;
     97 
     98 	if (drm->close)
     99 		close(drm->fd);
    100 
    101 	free(drm);
    102 }
    103 
    104 int drm_tegra_bo_new(struct drm_tegra_bo **bop, struct drm_tegra *drm,
    105 		     uint32_t flags, uint32_t size)
    106 {
    107 	struct drm_tegra_gem_create args;
    108 	struct drm_tegra_bo *bo;
    109 	int err;
    110 
    111 	if (!drm || size == 0 || !bop)
    112 		return -EINVAL;
    113 
    114 	bo = calloc(1, sizeof(*bo));
    115 	if (!bo)
    116 		return -ENOMEM;
    117 
    118 	atomic_set(&bo->ref, 1);
    119 	bo->flags = flags;
    120 	bo->size = size;
    121 	bo->drm = drm;
    122 
    123 	memset(&args, 0, sizeof(args));
    124 	args.flags = flags;
    125 	args.size = size;
    126 
    127 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_CREATE, &args,
    128 				  sizeof(args));
    129 	if (err < 0) {
    130 		err = -errno;
    131 		free(bo);
    132 		return err;
    133 	}
    134 
    135 	bo->handle = args.handle;
    136 
    137 	*bop = bo;
    138 
    139 	return 0;
    140 }
    141 
    142 int drm_tegra_bo_wrap(struct drm_tegra_bo **bop, struct drm_tegra *drm,
    143 		      uint32_t handle, uint32_t flags, uint32_t size)
    144 {
    145 	struct drm_tegra_bo *bo;
    146 
    147 	if (!drm || !bop)
    148 		return -EINVAL;
    149 
    150 	bo = calloc(1, sizeof(*bo));
    151 	if (!bo)
    152 		return -ENOMEM;
    153 
    154 	atomic_set(&bo->ref, 1);
    155 	bo->handle = handle;
    156 	bo->flags = flags;
    157 	bo->size = size;
    158 	bo->drm = drm;
    159 
    160 	*bop = bo;
    161 
    162 	return 0;
    163 }
    164 
    165 int drm_tegra_bo_name_ref(struct drm_tegra *drm, uint32_t name, uint32_t size,
    166 			 struct drm_tegra_bo **bop)
    167 {
    168 	struct drm_tegra_bo *bo;
    169 	struct drm_gem_open open_args;
    170 	struct drm_gem_close close_args;
    171 	int ret;
    172 
    173 	memset(&open_args, 0, sizeof(open_args));
    174 
    175 	open_args.name = name;
    176 
    177 	ret = drmIoctl(drm->fd, DRM_IOCTL_GEM_OPEN, &open_args);
    178 	if (ret)
    179 		return ret;
    180 
    181 	ret = drm_tegra_bo_wrap(bop, drm, open_args.handle, 0, size);
    182 	if (ret)
    183 		goto err;
    184 
    185 	(*bop)->name = name;
    186 
    187 	return 0;
    188 
    189 err:
    190 	memset(&close_args, 0, sizeof(close_args));
    191 	close_args.handle = open_args.handle;
    192 	drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &close_args);
    193 
    194 	return ret;
    195 }
    196 
    197 int drm_tegra_bo_name_get(struct drm_tegra_bo *bo, uint32_t *name)
    198 {
    199 	struct drm_gem_flink args;
    200 	int ret;
    201 
    202 	args.handle =  bo->handle;
    203 
    204 	*name = bo->name;
    205 	if (*name && *name != ~0U)
    206 		return 0;
    207 
    208 	ret = drmIoctl(bo->drm->fd, DRM_IOCTL_GEM_FLINK, &args);
    209 	if (ret) {
    210 		*name = 0;
    211 		return ret;
    212 	}
    213 
    214 	bo->name = args.name;
    215 	*name = bo->name;
    216 
    217 	return 0;
    218 }
    219 
    220 struct drm_tegra_bo *drm_tegra_bo_ref(struct drm_tegra_bo *bo)
    221 {
    222 	if (bo)
    223 		atomic_inc(&bo->ref);
    224 
    225 	return bo;
    226 }
    227 
    228 void drm_tegra_bo_unref(struct drm_tegra_bo *bo)
    229 {
    230 	if (bo && atomic_dec_and_test(&bo->ref))
    231 		drm_tegra_bo_free(bo);
    232 }
    233 
    234 int drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle)
    235 {
    236 	if (!bo || !handle)
    237 		return -EINVAL;
    238 
    239 	*handle = bo->handle;
    240 
    241 	return 0;
    242 }
    243 
    244 int drm_tegra_bo_map(struct drm_tegra_bo *bo, void **ptr)
    245 {
    246 	struct drm_tegra *drm = bo->drm;
    247 
    248 	if (!bo->map) {
    249 		struct drm_tegra_gem_mmap args;
    250 		int err;
    251 
    252 		memset(&args, 0, sizeof(args));
    253 		args.handle = bo->handle;
    254 
    255 		err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_MMAP, &args,
    256 					  sizeof(args));
    257 		if (err < 0)
    258 			return -errno;
    259 
    260 		bo->offset = args.offset;
    261 
    262 		bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
    263 			       drm->fd, bo->offset);
    264 		if (bo->map == MAP_FAILED) {
    265 			bo->map = NULL;
    266 			return -errno;
    267 		}
    268 	}
    269 
    270 	if (ptr)
    271 		*ptr = bo->map;
    272 
    273 	return 0;
    274 }
    275 
    276 int drm_tegra_bo_unmap(struct drm_tegra_bo *bo)
    277 {
    278 	if (!bo)
    279 		return -EINVAL;
    280 
    281 	if (!bo->map)
    282 		return 0;
    283 
    284 	if (munmap(bo->map, bo->size))
    285 		return -errno;
    286 
    287 	bo->map = NULL;
    288 
    289 	return 0;
    290 }
    291 
    292 int drm_tegra_bo_get_flags(struct drm_tegra_bo *bo, uint32_t *flags)
    293 {
    294 	struct drm_tegra_gem_get_flags args;
    295 	struct drm_tegra *drm = bo->drm;
    296 	int err;
    297 
    298 	if (!bo)
    299 		return -EINVAL;
    300 
    301 	memset(&args, 0, sizeof(args));
    302 	args.handle = bo->handle;
    303 
    304 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_FLAGS, &args,
    305 				  sizeof(args));
    306 	if (err < 0)
    307 		return -errno;
    308 
    309 	if (flags)
    310 		*flags = args.flags;
    311 
    312 	return 0;
    313 }
    314 
    315 int drm_tegra_bo_set_flags(struct drm_tegra_bo *bo, uint32_t flags)
    316 {
    317 	struct drm_tegra_gem_get_flags args;
    318 	struct drm_tegra *drm = bo->drm;
    319 	int err;
    320 
    321 	if (!bo)
    322 		return -EINVAL;
    323 
    324 	memset(&args, 0, sizeof(args));
    325 	args.handle = bo->handle;
    326 	args.flags = flags;
    327 
    328 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_FLAGS, &args,
    329 				  sizeof(args));
    330 	if (err < 0)
    331 		return -errno;
    332 
    333 	return 0;
    334 }
    335 
    336 int drm_tegra_bo_get_tiling(struct drm_tegra_bo *bo,
    337 			    struct drm_tegra_bo_tiling *tiling)
    338 {
    339 	struct drm_tegra_gem_get_tiling args;
    340 	struct drm_tegra *drm = bo->drm;
    341 	int err;
    342 
    343 	if (!bo)
    344 		return -EINVAL;
    345 
    346 	memset(&args, 0, sizeof(args));
    347 	args.handle = bo->handle;
    348 
    349 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_TILING, &args,
    350 				  sizeof(args));
    351 	if (err < 0)
    352 		return -errno;
    353 
    354 	if (tiling) {
    355 		tiling->mode = args.mode;
    356 		tiling->value = args.value;
    357 	}
    358 
    359 	return 0;
    360 }
    361 
    362 int drm_tegra_bo_set_tiling(struct drm_tegra_bo *bo,
    363 			    const struct drm_tegra_bo_tiling *tiling)
    364 {
    365 	struct drm_tegra_gem_set_tiling args;
    366 	struct drm_tegra *drm = bo->drm;
    367 	int err;
    368 
    369 	if (!bo)
    370 		return -EINVAL;
    371 
    372 	memset(&args, 0, sizeof(args));
    373 	args.handle = bo->handle;
    374 	args.mode = tiling->mode;
    375 	args.value = tiling->value;
    376 
    377 	err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_TILING, &args,
    378 				  sizeof(args));
    379 	if (err < 0)
    380 		return -errno;
    381 
    382 	return 0;
    383 }
    384