1 /*
2 * Copyright 2015 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
7 #ifdef DRV_MEDIATEK
8
9 // clang-format off
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <inttypes.h>
13 #include <poll.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/mman.h>
17 #include <unistd.h>
18 #include <xf86drm.h>
19 #include <mediatek_drm.h>
20 // clang-format on
21
22 #include "drv_helpers.h"
23 #include "drv_priv.h"
24 #include "util.h"
25
26 #define TILE_TYPE_LINEAR 0
27
28 #if defined(MTK_MT8183) || defined(MTK_MT8186)
29 #define SUPPORTS_YUV422_AND_HIGH_BIT_DEPTH_TEXTURING
30 #endif
31
32 // All platforms except MT8173 should USE_NV12_FOR_HW_VIDEO_DECODING.
33 #if defined(MTK_MT8183) || defined(MTK_MT8186) || defined(MTK_MT8192) || defined(MTK_MT8195)
34 #define USE_NV12_FOR_HW_VIDEO_DECODING
35 #else
36 #define DONT_USE_64_ALIGNMENT_FOR_VIDEO_BUFFERS
37 #endif
38
39 struct mediatek_private_map_data {
40 void *cached_addr;
41 void *gem_addr;
42 int prime_fd;
43 };
44
45 static const uint32_t render_target_formats[] = { DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888,
46 DRM_FORMAT_RGB565, DRM_FORMAT_XBGR8888,
47 DRM_FORMAT_XRGB8888 };
48
49 // clang-format off
50 static const uint32_t texture_source_formats[] = {
51 #ifdef SUPPORTS_YUV422_AND_HIGH_BIT_DEPTH_TEXTURING
52 DRM_FORMAT_NV21,
53 DRM_FORMAT_YUYV,
54 DRM_FORMAT_ABGR2101010,
55 DRM_FORMAT_ABGR16161616F,
56 #endif
57 DRM_FORMAT_NV12,
58 DRM_FORMAT_YVU420,
59 DRM_FORMAT_YVU420_ANDROID
60 };
61
62 static const uint32_t video_yuv_formats[] = {
63 DRM_FORMAT_NV21,
64 DRM_FORMAT_NV12,
65 DRM_FORMAT_YVU420,
66 DRM_FORMAT_YVU420_ANDROID
67 };
68 // clang-format on
69
is_video_yuv_format(uint32_t format)70 static bool is_video_yuv_format(uint32_t format)
71 {
72 size_t i;
73 for (i = 0; i < ARRAY_SIZE(video_yuv_formats); ++i) {
74 if (format == video_yuv_formats[i])
75 return true;
76 }
77 return false;
78 }
79
mediatek_init(struct driver * drv)80 static int mediatek_init(struct driver *drv)
81 {
82 struct format_metadata metadata;
83
84 drv_add_combinations(drv, render_target_formats, ARRAY_SIZE(render_target_formats),
85 &LINEAR_METADATA, BO_USE_RENDER_MASK | BO_USE_SCANOUT);
86
87 drv_add_combinations(drv, texture_source_formats, ARRAY_SIZE(texture_source_formats),
88 &LINEAR_METADATA, BO_USE_TEXTURE_MASK);
89
90 drv_add_combination(drv, DRM_FORMAT_R8, &LINEAR_METADATA, BO_USE_SW_MASK | BO_USE_LINEAR);
91
92 /* Android CTS tests require this. */
93 drv_add_combination(drv, DRM_FORMAT_BGR888, &LINEAR_METADATA, BO_USE_SW_MASK);
94
95 /* Support BO_USE_HW_VIDEO_DECODER for protected content minigbm allocations. */
96 metadata.tiling = TILE_TYPE_LINEAR;
97 metadata.priority = 1;
98 metadata.modifier = DRM_FORMAT_MOD_LINEAR;
99 drv_modify_combination(drv, DRM_FORMAT_YVU420, &metadata, BO_USE_HW_VIDEO_DECODER);
100 drv_modify_combination(drv, DRM_FORMAT_YVU420_ANDROID, &metadata, BO_USE_HW_VIDEO_DECODER);
101 #ifdef USE_NV12_FOR_HW_VIDEO_DECODING
102 // TODO(hiroh): Switch to use NV12 for video decoder on MT8173 as well.
103 drv_modify_combination(drv, DRM_FORMAT_NV12, &metadata, BO_USE_HW_VIDEO_DECODER);
104 #endif
105
106 /*
107 * R8 format is used for Android's HAL_PIXEL_FORMAT_BLOB for input/output from
108 * hardware decoder/encoder.
109 */
110 drv_modify_combination(drv, DRM_FORMAT_R8, &metadata,
111 BO_USE_HW_VIDEO_DECODER | BO_USE_HW_VIDEO_ENCODER |
112 BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE);
113
114 /* NV12 format for encoding and display. */
115 drv_modify_combination(drv, DRM_FORMAT_NV12, &metadata,
116 BO_USE_SCANOUT | BO_USE_HW_VIDEO_ENCODER | BO_USE_CAMERA_READ |
117 BO_USE_CAMERA_WRITE);
118
119 #ifdef MTK_MT8183
120 /* Only for MT8183 Camera subsystem */
121 drv_modify_combination(drv, DRM_FORMAT_NV21, &metadata,
122 BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE);
123 drv_modify_combination(drv, DRM_FORMAT_YUYV, &metadata,
124 BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE);
125 drv_modify_combination(drv, DRM_FORMAT_YVU420, &metadata,
126 BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE);
127 /* Private formats for private reprocessing in camera */
128 drv_add_combination(drv, DRM_FORMAT_MTISP_SXYZW10, &metadata,
129 BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_SW_MASK);
130 #endif
131
132 return drv_modify_linear_combinations(drv);
133 }
134
mediatek_bo_create_with_modifiers(struct bo * bo,uint32_t width,uint32_t height,uint32_t format,const uint64_t * modifiers,uint32_t count)135 static int mediatek_bo_create_with_modifiers(struct bo *bo, uint32_t width, uint32_t height,
136 uint32_t format, const uint64_t *modifiers,
137 uint32_t count)
138 {
139 int ret;
140 size_t plane;
141 uint32_t stride;
142 struct drm_mtk_gem_create gem_create = { 0 };
143 /*
144 * We identify the ChromeOS Camera App buffers via these two USE flags. Those buffers need
145 * the same alignment as the video hardware encoding.
146 */
147 const bool is_camera_preview =
148 (bo->meta.use_flags & BO_USE_SCANOUT) && (bo->meta.use_flags & BO_USE_CAMERA_WRITE);
149
150 if (!drv_has_modifier(modifiers, count, DRM_FORMAT_MOD_LINEAR)) {
151 errno = EINVAL;
152 drv_log("no usable modifier found\n");
153 return -EINVAL;
154 }
155
156 /*
157 * Since the ARM L1 cache line size is 64 bytes, align to that as a
158 * performance optimization, except for video buffers on certain platforms,
159 * these should only be accessed from the GPU and VCODEC subsystems (maybe
160 * also MDP), so it's better to align to macroblocks.
161 */
162 stride = drv_stride_from_format(format, width, 0);
163 #ifdef DONT_USE_64_ALIGNMENT_FOR_VIDEO_BUFFERS
164 const uint32_t alignment = is_video_yuv_format(format) ? 16 : 64;
165 stride = ALIGN(stride, alignment);
166 #else
167 stride = ALIGN(stride, 64);
168 #endif
169
170 if ((bo->meta.use_flags & BO_USE_HW_VIDEO_ENCODER) || is_camera_preview) {
171 uint32_t aligned_height = ALIGN(height, 32);
172 uint32_t padding[DRV_MAX_PLANES] = { 0 };
173
174 for (plane = 0; plane < bo->meta.num_planes; ++plane) {
175 uint32_t plane_stride = drv_stride_from_format(format, stride, plane);
176 padding[plane] = plane_stride *
177 (32 / drv_vertical_subsampling_from_format(format, plane));
178 }
179
180 drv_bo_from_format_and_padding(bo, stride, aligned_height, format, padding);
181 } else {
182 #ifdef SUPPORTS_YUV422_AND_HIGH_BIT_DEPTH_TEXTURING
183 /*
184 * JPEG Encoder Accelerator requires 16x16 alignment. We want the buffer
185 * from camera can be put in JEA directly so align the height to 16
186 * bytes.
187 */
188 if (format == DRM_FORMAT_NV12)
189 height = ALIGN(height, 16);
190 #endif
191 drv_bo_from_format(bo, stride, height, format);
192 }
193
194 gem_create.size = bo->meta.total_size;
195
196 ret = drmIoctl(bo->drv->fd, DRM_IOCTL_MTK_GEM_CREATE, &gem_create);
197 if (ret) {
198 drv_log("DRM_IOCTL_MTK_GEM_CREATE failed (size=%" PRIu64 ")\n", gem_create.size);
199 return -errno;
200 }
201
202 for (plane = 0; plane < bo->meta.num_planes; plane++)
203 bo->handles[plane].u32 = gem_create.handle;
204
205 return 0;
206 }
207
mediatek_bo_create(struct bo * bo,uint32_t width,uint32_t height,uint32_t format,uint64_t use_flags)208 static int mediatek_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
209 uint64_t use_flags)
210 {
211 uint64_t modifiers[] = { DRM_FORMAT_MOD_LINEAR };
212 return mediatek_bo_create_with_modifiers(bo, width, height, format, modifiers,
213 ARRAY_SIZE(modifiers));
214 }
215
mediatek_bo_map(struct bo * bo,struct vma * vma,size_t plane,uint32_t map_flags)216 static void *mediatek_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
217 {
218 int ret, prime_fd;
219 struct drm_mtk_gem_map_off gem_map = { 0 };
220 struct mediatek_private_map_data *priv;
221 void *addr = NULL;
222
223 gem_map.handle = bo->handles[0].u32;
224
225 ret = drmIoctl(bo->drv->fd, DRM_IOCTL_MTK_GEM_MAP_OFFSET, &gem_map);
226 if (ret) {
227 drv_log("DRM_IOCTL_MTK_GEM_MAP_OFFSET failed\n");
228 return MAP_FAILED;
229 }
230
231 prime_fd = drv_bo_get_plane_fd(bo, 0);
232 if (prime_fd < 0) {
233 drv_log("Failed to get a prime fd\n");
234 return MAP_FAILED;
235 }
236
237 addr = mmap(0, bo->meta.total_size, drv_get_prot(map_flags), MAP_SHARED, bo->drv->fd,
238 gem_map.offset);
239 if (addr == MAP_FAILED)
240 goto out_close_prime_fd;
241
242 vma->length = bo->meta.total_size;
243
244 priv = calloc(1, sizeof(*priv));
245 if (!priv)
246 goto out_unmap_addr;
247
248 if (bo->meta.use_flags & BO_USE_RENDERSCRIPT) {
249 priv->cached_addr = calloc(1, bo->meta.total_size);
250 if (!priv->cached_addr)
251 goto out_free_priv;
252
253 priv->gem_addr = addr;
254 addr = priv->cached_addr;
255 }
256
257 priv->prime_fd = prime_fd;
258 vma->priv = priv;
259
260 return addr;
261
262 out_free_priv:
263 free(priv);
264 out_unmap_addr:
265 munmap(addr, bo->meta.total_size);
266 out_close_prime_fd:
267 close(prime_fd);
268 return MAP_FAILED;
269 }
270
mediatek_bo_unmap(struct bo * bo,struct vma * vma)271 static int mediatek_bo_unmap(struct bo *bo, struct vma *vma)
272 {
273 if (vma->priv) {
274 struct mediatek_private_map_data *priv = vma->priv;
275
276 if (priv->cached_addr) {
277 vma->addr = priv->gem_addr;
278 free(priv->cached_addr);
279 }
280
281 close(priv->prime_fd);
282 free(priv);
283 vma->priv = NULL;
284 }
285
286 return munmap(vma->addr, vma->length);
287 }
288
mediatek_bo_invalidate(struct bo * bo,struct mapping * mapping)289 static int mediatek_bo_invalidate(struct bo *bo, struct mapping *mapping)
290 {
291 struct mediatek_private_map_data *priv = mapping->vma->priv;
292
293 if (priv) {
294 struct pollfd fds = {
295 .fd = priv->prime_fd,
296 };
297
298 if (mapping->vma->map_flags & BO_MAP_WRITE)
299 fds.events |= POLLOUT;
300
301 if (mapping->vma->map_flags & BO_MAP_READ)
302 fds.events |= POLLIN;
303
304 poll(&fds, 1, -1);
305 if (fds.revents != fds.events)
306 drv_log("poll prime_fd failed\n");
307
308 if (priv->cached_addr)
309 memcpy(priv->cached_addr, priv->gem_addr, bo->meta.total_size);
310 }
311
312 return 0;
313 }
314
mediatek_bo_flush(struct bo * bo,struct mapping * mapping)315 static int mediatek_bo_flush(struct bo *bo, struct mapping *mapping)
316 {
317 struct mediatek_private_map_data *priv = mapping->vma->priv;
318 if (priv && priv->cached_addr && (mapping->vma->map_flags & BO_MAP_WRITE))
319 memcpy(priv->gem_addr, priv->cached_addr, bo->meta.total_size);
320
321 return 0;
322 }
323
mediatek_resolve_format_and_use_flags(struct driver * drv,uint32_t format,uint64_t use_flags,uint32_t * out_format,uint64_t * out_use_flags)324 static void mediatek_resolve_format_and_use_flags(struct driver *drv, uint32_t format,
325 uint64_t use_flags, uint32_t *out_format,
326 uint64_t *out_use_flags)
327 {
328 *out_format = format;
329 *out_use_flags = use_flags;
330 switch (format) {
331 case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED:
332 #ifdef MTK_MT8183
333 /* Only MT8183 Camera subsystem offers private reprocessing
334 * capability. CAMERA_READ indicates the buffer is intended for
335 * reprocessing and hence given the private format for MTK. */
336 if (use_flags & BO_USE_CAMERA_READ) {
337 *out_format = DRM_FORMAT_MTISP_SXYZW10;
338 break;
339 }
340 #endif
341 if (use_flags & BO_USE_CAMERA_WRITE) {
342 *out_format = DRM_FORMAT_NV12;
343 break;
344 }
345
346 /* HACK: See b/28671744 */
347 *out_format = DRM_FORMAT_XBGR8888;
348 *out_use_flags &= ~BO_USE_HW_VIDEO_ENCODER;
349 break;
350 case DRM_FORMAT_FLEX_YCbCr_420_888:
351 #ifdef USE_NV12_FOR_HW_VIDEO_DECODING
352 // TODO(hiroh): Switch to use NV12 for video decoder on MT8173 as well.
353 if (use_flags & (BO_USE_HW_VIDEO_DECODER)) {
354 *out_format = DRM_FORMAT_NV12;
355 break;
356 }
357 #endif
358 if (use_flags &
359 (BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_ENCODER)) {
360 *out_format = DRM_FORMAT_NV12;
361 break;
362 }
363
364 /* HACK: See b/139714614 */
365 *out_format = DRM_FORMAT_YVU420;
366 *out_use_flags &= ~BO_USE_SCANOUT;
367 break;
368 default:
369 break;
370 }
371 /* Mediatek doesn't support YUV overlays */
372 if (is_video_yuv_format(format))
373 *out_use_flags &= ~BO_USE_SCANOUT;
374 }
375
376 const struct backend backend_mediatek = {
377 .name = "mediatek",
378 .init = mediatek_init,
379 .bo_create = mediatek_bo_create,
380 .bo_create_with_modifiers = mediatek_bo_create_with_modifiers,
381 .bo_destroy = drv_gem_bo_destroy,
382 .bo_import = drv_prime_bo_import,
383 .bo_map = mediatek_bo_map,
384 .bo_unmap = mediatek_bo_unmap,
385 .bo_invalidate = mediatek_bo_invalidate,
386 .bo_flush = mediatek_bo_flush,
387 .resolve_format_and_use_flags = mediatek_resolve_format_and_use_flags,
388 };
389
390 #endif
391