blob: 28f98c642832fd62b15e7ad640dcb9c651141d9a [file] [log] [blame]
Stéphane Marchesin25a26062014-09-12 16:18:59 -07001/*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Gurchetan Singh46faf6b2016-08-05 14:40:07 -07007#ifdef DRV_TEGRA
Stéphane Marchesin25a26062014-09-12 16:18:59 -07008
Ilja H. Friedelf9d2ab72015-04-09 14:08:36 -07009#include <stdio.h>
Stéphane Marchesin25a26062014-09-12 16:18:59 -070010#include <string.h>
Gurchetan Singhef920532016-08-12 16:38:25 -070011#include <sys/mman.h>
Stéphane Marchesin25a26062014-09-12 16:18:59 -070012#include <xf86drm.h>
13#include <tegra_drm.h>
14
Gurchetan Singh46faf6b2016-08-05 14:40:07 -070015#include "drv_priv.h"
Stéphane Marchesin25a26062014-09-12 16:18:59 -070016#include "helpers.h"
Yuly Novikov96c7a3b2015-12-08 22:48:29 -050017#include "util.h"
Stéphane Marchesin25a26062014-09-12 16:18:59 -070018
Lauri Peltonen7842d8f2014-12-17 23:01:37 -080019/*
20 * GOB (Group Of Bytes) is the basic unit of the blocklinear layout.
21 * GOBs are arranged to blocks, where the height of the block (measured
22 * in GOBs) is configurable.
23 */
24#define NV_BLOCKLINEAR_GOB_HEIGHT 8
25#define NV_BLOCKLINEAR_GOB_WIDTH 64
26#define NV_DEFAULT_BLOCK_HEIGHT_LOG2 4
27#define NV_PREFERRED_PAGE_SIZE (128 * 1024)
28
29enum nv_mem_kind
Stéphane Marchesin25a26062014-09-12 16:18:59 -070030{
Lauri Peltonen7842d8f2014-12-17 23:01:37 -080031 NV_MEM_KIND_PITCH = 0,
Vince Hsu0fd11422016-05-19 17:46:08 +080032 NV_MEM_KIND_C32_2CRA = 0xdb,
Lauri Peltonen7842d8f2014-12-17 23:01:37 -080033 NV_MEM_KIND_GENERIC_16Bx2 = 0xfe,
34};
35
36static int compute_block_height_log2(int height)
37{
38 int block_height_log2 = NV_DEFAULT_BLOCK_HEIGHT_LOG2;
39
40 if (block_height_log2 > 0) {
41 /* Shrink, if a smaller block height could cover the whole
42 * surface height. */
43 int proposed = NV_BLOCKLINEAR_GOB_HEIGHT << (block_height_log2 - 1);
44 while (proposed >= height) {
45 block_height_log2--;
46 if (block_height_log2 == 0)
47 break;
48 proposed /= 2;
49 }
50 }
51 return block_height_log2;
52}
53
Lauri Peltonen7842d8f2014-12-17 23:01:37 -080054static void compute_layout_blocklinear(int width, int height, int format,
Stéphane Marchesinec88e892015-11-03 16:14:59 -080055 enum nv_mem_kind *kind,
56 uint32_t *block_height_log2,
Lauri Peltonen7842d8f2014-12-17 23:01:37 -080057 uint32_t *stride, uint32_t *size)
58{
Gurchetan Singh83dc4fb2016-07-19 15:52:33 -070059 int pitch = drv_stride_from_format(format, width, 0);
Lauri Peltonen7842d8f2014-12-17 23:01:37 -080060
61 /* Align to blocklinear blocks. */
Yuly Novikov96c7a3b2015-12-08 22:48:29 -050062 pitch = ALIGN(pitch, NV_BLOCKLINEAR_GOB_WIDTH);
Lauri Peltonen7842d8f2014-12-17 23:01:37 -080063
64 /* Compute padded height. */
65 *block_height_log2 = compute_block_height_log2(height);
66 int block_height = 1 << *block_height_log2;
Stéphane Marchesinec88e892015-11-03 16:14:59 -080067 int padded_height =
Yuly Novikov96c7a3b2015-12-08 22:48:29 -050068 ALIGN(height, NV_BLOCKLINEAR_GOB_HEIGHT * block_height);
Lauri Peltonen7842d8f2014-12-17 23:01:37 -080069
70 int bytes = pitch * padded_height;
71
72 /* Pad the allocation to the preferred page size.
73 * This will reduce the required page table size (see discussion in NV
74 * bug 1321091), and also acts as a WAR for NV bug 1325421.
75 */
Yuly Novikov96c7a3b2015-12-08 22:48:29 -050076 bytes = ALIGN(bytes, NV_PREFERRED_PAGE_SIZE);
Lauri Peltonen7842d8f2014-12-17 23:01:37 -080077
Vince Hsu0fd11422016-05-19 17:46:08 +080078 *kind = NV_MEM_KIND_C32_2CRA;
Lauri Peltonen7842d8f2014-12-17 23:01:37 -080079 *stride = pitch;
80 *size = bytes;
81}
82
83static void compute_layout_linear(int width, int height, int format,
84 uint32_t *stride, uint32_t *size)
85{
Gurchetan Singh83dc4fb2016-07-19 15:52:33 -070086 *stride = drv_stride_from_format(format, width, 0);
Lauri Peltonen7842d8f2014-12-17 23:01:37 -080087 *size = *stride * height;
88}
89
Gurchetan Singhd7c84fd2016-08-16 18:18:24 -070090static int tegra_bo_create(struct bo *bo, uint32_t width, uint32_t height,
91 uint32_t format, uint32_t flags)
Lauri Peltonen7842d8f2014-12-17 23:01:37 -080092{
93 uint32_t size, stride, block_height_log2 = 0;
94 enum nv_mem_kind kind = NV_MEM_KIND_PITCH;
Stéphane Marchesin25a26062014-09-12 16:18:59 -070095 struct drm_tegra_gem_create gem_create;
96 int ret;
97
Gurchetan Singh46faf6b2016-08-05 14:40:07 -070098 if (flags & DRV_BO_USE_RENDERING)
Lauri Peltonen7842d8f2014-12-17 23:01:37 -080099 compute_layout_blocklinear(width, height, format, &kind,
100 &block_height_log2, &stride, &size);
101 else
102 compute_layout_linear(width, height, format, &stride, &size);
103
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700104 memset(&gem_create, 0, sizeof(gem_create));
105 gem_create.size = size;
106 gem_create.flags = 0;
107
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700108 ret = drmIoctl(bo->drv->fd, DRM_IOCTL_TEGRA_GEM_CREATE, &gem_create);
Ilja H. Friedelf9d2ab72015-04-09 14:08:36 -0700109 if (ret) {
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700110 fprintf(stderr, "drv: DRM_IOCTL_TEGRA_GEM_CREATE failed "
Ilja H. Friedelf9d2ab72015-04-09 14:08:36 -0700111 "(size=%zu)\n", size);
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700112 return ret;
Ilja H. Friedelf9d2ab72015-04-09 14:08:36 -0700113 }
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700114
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500115 bo->handles[0].u32 = gem_create.handle;
116 bo->offsets[0] = 0;
Gurchetan Singha40ca9e2016-08-29 19:51:45 -0700117 bo->total_size = bo->sizes[0] = size;
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500118 bo->strides[0] = stride;
Lauri Peltonen7842d8f2014-12-17 23:01:37 -0800119
120 if (kind != NV_MEM_KIND_PITCH) {
121 struct drm_tegra_gem_set_tiling gem_tile;
122
123 memset(&gem_tile, 0, sizeof(gem_tile));
Yuly Novikov96c7a3b2015-12-08 22:48:29 -0500124 gem_tile.handle = bo->handles[0].u32;
Lauri Peltonen7842d8f2014-12-17 23:01:37 -0800125 gem_tile.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
126 gem_tile.value = block_height_log2;
127
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700128 ret = drmCommandWriteRead(bo->drv->fd, DRM_TEGRA_GEM_SET_TILING,
Stéphane Marchesinec88e892015-11-03 16:14:59 -0800129 &gem_tile, sizeof(gem_tile));
Lauri Peltonen7842d8f2014-12-17 23:01:37 -0800130 if (ret < 0) {
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700131 drv_gem_bo_destroy(bo);
Lauri Peltonen7842d8f2014-12-17 23:01:37 -0800132 return ret;
133 }
134
135 /* Encode blocklinear parameters for EGLImage creation. */
Vince Hsuf9e7c4c2016-05-19 18:11:56 +0800136 bo->tiling = (kind & 0xff) |
Lauri Peltonen7842d8f2014-12-17 23:01:37 -0800137 ((block_height_log2 & 0xf) << 8);
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700138 bo->format_modifiers[0] = drv_fourcc_mod_code(NV, bo->tiling);
Lauri Peltonen7842d8f2014-12-17 23:01:37 -0800139 }
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700140
141 return 0;
142}
143
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700144static void *tegra_bo_map(struct bo *bo, struct map_info *data, size_t plane)
Gurchetan Singhef920532016-08-12 16:38:25 -0700145{
146 int ret;
147 struct drm_tegra_gem_mmap gem_map;
148
149 memset(&gem_map, 0, sizeof(gem_map));
150 gem_map.handle = bo->handles[0].u32;
151
152 ret = drmCommandWriteRead(bo->drv->fd, DRM_TEGRA_GEM_MMAP, &gem_map,
153 sizeof(gem_map));
154 if (ret < 0) {
155 fprintf(stderr, "drv: DRM_TEGRA_GEM_MMAP failed\n");
156 return MAP_FAILED;
157 }
158
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700159 data->length = bo->total_size;
160
Gurchetan Singha40ca9e2016-08-29 19:51:45 -0700161 return mmap(0, bo->total_size, PROT_READ | PROT_WRITE, MAP_SHARED,
Gurchetan Singhef920532016-08-12 16:38:25 -0700162 bo->drv->fd, gem_map.offset);
163}
164
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700165const struct backend backend_tegra =
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700166{
167 .name = "tegra",
Gurchetan Singhd7c84fd2016-08-16 18:18:24 -0700168 .bo_create = tegra_bo_create,
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700169 .bo_destroy = drv_gem_bo_destroy,
Gurchetan Singhd7c84fd2016-08-16 18:18:24 -0700170 .bo_map = tegra_bo_map,
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700171 .format_list = {
Lauri Peltonen7842d8f2014-12-17 23:01:37 -0800172 /* Linear support */
Gurchetan Singh56662da2016-09-12 16:21:29 -0700173 {DRV_FORMAT_XRGB8888, DRV_BO_USE_SCANOUT | DRV_BO_USE_CURSOR | DRV_BO_USE_LINEAR
174 | DRV_BO_USE_SW_READ_OFTEN | DRV_BO_USE_SW_WRITE_OFTEN},
175 {DRV_FORMAT_ARGB8888, DRV_BO_USE_SCANOUT | DRV_BO_USE_CURSOR | DRV_BO_USE_LINEAR
176 | DRV_BO_USE_SW_READ_OFTEN | DRV_BO_USE_SW_WRITE_OFTEN},
Lauri Peltonen7842d8f2014-12-17 23:01:37 -0800177 /* Blocklinear support */
Gurchetan Singhbfba8c22016-08-16 17:57:10 -0700178 {DRV_FORMAT_XRGB8888, DRV_BO_USE_SCANOUT | DRV_BO_USE_RENDERING |
Gurchetan Singh56662da2016-09-12 16:21:29 -0700179 DRV_BO_USE_SW_READ_RARELY | DRV_BO_USE_SW_WRITE_RARELY},
Gurchetan Singhbfba8c22016-08-16 17:57:10 -0700180 {DRV_FORMAT_ARGB8888, DRV_BO_USE_SCANOUT | DRV_BO_USE_RENDERING |
Gurchetan Singh56662da2016-09-12 16:21:29 -0700181 DRV_BO_USE_SW_READ_RARELY | DRV_BO_USE_SW_WRITE_RARELY},
Stéphane Marchesin25a26062014-09-12 16:18:59 -0700182 }
183};
184
185#endif