1/*
2 * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
3 * Copyright (c) Imagination Technologies Limited, UK
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 *    Waldo Bastian <waldo.bastian@intel.com>
27 *
28 */
29
30#include <wsbm/wsbm_manager.h>
31
32#include "psb_def.h"
33#include "psb_surface.h"
34#include "psb_drv_debug.h"
35
36/*
37 * Create surface
38 */
39VAStatus psb_surface_create(psb_driver_data_p driver_data,
40                            int width, int height, int fourcc, unsigned int flags,
41                            psb_surface_p psb_surface /* out */
42                           )
43{
44    int ret = 0;
45    int buffer_type = psb_bt_surface;
46
47#ifndef BAYTRAIL
48    if ((flags & IS_ROTATED) || (driver_data->render_mode & VA_RENDER_MODE_LOCAL_OVERLAY))
49        buffer_type = psb_bt_surface_tt;
50#endif
51
52#ifdef PSBVIDEO_MSVDX_DEC_TILING
53    int tiling = GET_SURFACE_INFO_tiling(psb_surface);
54    if (tiling)
55        buffer_type = psb_bt_surface_tiling;
56#endif
57
58    if (fourcc == VA_FOURCC_NV12) {
59        if ((width <= 0) || (width * height > 5120 * 5120) || (height <= 0)) {
60            return VA_STATUS_ERROR_ALLOCATION_FAILED;
61        }
62
63        if (0) {
64            ;
65        } else if (512 >= width) {
66            psb_surface->stride_mode = STRIDE_512;
67            psb_surface->stride = 512;
68        } else if (1024 >= width) {
69            psb_surface->stride_mode = STRIDE_1024;
70            psb_surface->stride = 1024;
71        } else if (1280 >= width) {
72            psb_surface->stride_mode = STRIDE_1280;
73            psb_surface->stride = 1280;
74#ifdef PSBVIDEO_MSVDX_DEC_TILING
75            if (tiling) {
76                psb_surface->stride_mode = STRIDE_2048;
77                psb_surface->stride = 2048;
78            }
79#endif
80        } else if (2048 >= width) {
81            psb_surface->stride_mode = STRIDE_2048;
82            psb_surface->stride = 2048;
83        } else if (4096 >= width) {
84            psb_surface->stride_mode = STRIDE_4096;
85            psb_surface->stride = 4096;
86        } else {
87            psb_surface->stride_mode = STRIDE_NA;
88            psb_surface->stride = (width + 0x3f) & ~0x3f;
89        }
90
91        psb_surface->luma_offset = 0;
92        psb_surface->chroma_offset = psb_surface->stride * height;
93        psb_surface->size = (psb_surface->stride * height * 3) / 2;
94        psb_surface->extra_info[4] = VA_FOURCC_NV12;
95    } else if (fourcc == VA_FOURCC_RGBA) {
96        unsigned int pitchAlignMask = 63;
97        psb_surface->stride_mode = STRIDE_NA;
98        psb_surface->stride = (width * 4 + pitchAlignMask) & ~pitchAlignMask;;
99        psb_surface->luma_offset = 0;
100        psb_surface->chroma_offset = 0;
101        psb_surface->size = psb_surface->stride * height;
102        psb_surface->extra_info[4] = VA_FOURCC_RGBA;
103    } else if (fourcc == VA_FOURCC_YV16) {
104        if ((width <= 0) || (width * height > 5120 * 5120) || (height <= 0)) {
105            return VA_STATUS_ERROR_ALLOCATION_FAILED;
106        }
107
108        if (0) {
109            ;
110        } else if (512 >= width) {
111            psb_surface->stride_mode = STRIDE_512;
112            psb_surface->stride = 512;
113        } else if (1024 >= width) {
114            psb_surface->stride_mode = STRIDE_1024;
115            psb_surface->stride = 1024;
116        } else if (1280 >= width) {
117            psb_surface->stride_mode = STRIDE_1280;
118            psb_surface->stride = 1280;
119#ifdef PSBVIDEO_MSVDX_DEC_TILING
120            if (tiling) {
121                psb_surface->stride_mode = STRIDE_2048;
122                psb_surface->stride = 2048;
123            }
124#endif
125        } else if (2048 >= width) {
126            psb_surface->stride_mode = STRIDE_2048;
127            psb_surface->stride = 2048;
128        } else if (4096 >= width) {
129            psb_surface->stride_mode = STRIDE_4096;
130            psb_surface->stride = 4096;
131        } else {
132            psb_surface->stride_mode = STRIDE_NA;
133            psb_surface->stride = (width + 0x3f) & ~0x3f;
134        }
135
136        psb_surface->luma_offset = 0;
137        psb_surface->chroma_offset = psb_surface->stride * height;
138        psb_surface->size = psb_surface->stride * height * 2;
139        psb_surface->extra_info[4] = VA_FOURCC_YV16;
140    } else if (fourcc == VA_FOURCC_YV32) {
141        psb_surface->stride_mode = STRIDE_NA;
142        psb_surface->stride = (width + 0x3f) & ~0x3f; /*round up to 16 */
143        psb_surface->luma_offset = 0;
144        psb_surface->chroma_offset = psb_surface->stride * height;
145        psb_surface->size = psb_surface->stride * height * 4;
146        psb_surface->extra_info[4] = VA_FOURCC_YV32;
147    }
148
149    if (flags & IS_PROTECTED)
150        SET_SURFACE_INFO_protect(psb_surface, 1);
151
152    ret = psb_buffer_create(driver_data, psb_surface->size, buffer_type, &psb_surface->buf);
153
154    return ret ? VA_STATUS_ERROR_ALLOCATION_FAILED : VA_STATUS_SUCCESS;
155}
156
157
158
159VAStatus psb_surface_create_for_userptr(
160    psb_driver_data_p driver_data,
161    int width, int height,
162    unsigned size, /* total buffer size need to be allocated */
163    unsigned int __maybe_unused fourcc, /* expected fourcc */
164    unsigned int luma_stride, /* luma stride, could be width aligned with a special value */
165    unsigned int __maybe_unused chroma_u_stride, /* chroma stride */
166    unsigned int __maybe_unused chroma_v_stride,
167    unsigned int luma_offset, /* could be 0 */
168    unsigned int chroma_u_offset, /* UV offset from the beginning of the memory */
169    unsigned int __maybe_unused chroma_v_offset,
170    psb_surface_p psb_surface /* out */
171)
172{
173    int ret;
174
175    if ((width <= 0) || (width > 5120) || (height <= 0) || (height > 5120))
176        return VA_STATUS_ERROR_ALLOCATION_FAILED;
177
178    psb_surface->stride_mode = STRIDE_NA;
179    psb_surface->stride = luma_stride;
180
181
182    psb_surface->luma_offset = luma_offset;
183    psb_surface->chroma_offset = chroma_u_offset;
184    psb_surface->size = size;
185    psb_surface->extra_info[4] = VA_FOURCC_NV12;
186    psb_surface->extra_info[8] = VA_FOURCC_NV12;
187
188    ret = psb_buffer_create(driver_data, psb_surface->size, psb_bt_cpu_vpu_shared, &psb_surface->buf);
189
190    return ret ? VA_STATUS_ERROR_ALLOCATION_FAILED : VA_STATUS_SUCCESS;
191}
192
193VAStatus psb_surface_create_from_kbuf(
194    psb_driver_data_p driver_data,
195    int width, int height,
196    unsigned size, /* total buffer size need to be allocated */
197    unsigned int __maybe_unused fourcc, /* expected fourcc */
198    int __maybe_unused kbuf_handle,
199    unsigned int luma_stride, /* luma stride, could be width aligned with a special value */
200    unsigned int __maybe_unused chroma_u_stride, /* chroma stride */
201    unsigned int __maybe_unused chroma_v_stride,
202    unsigned int __maybe_unused luma_offset, /* could be 0 */
203    unsigned int chroma_u_offset, /* UV offset from the beginning of the memory */
204    unsigned int __maybe_unused chroma_v_offset,
205    psb_surface_p psb_surface /* out */
206)
207{
208    int ret;
209
210    if ((width <= 0) || (width > 5120) || (height <= 0) || (height > 5120))
211        return VA_STATUS_ERROR_ALLOCATION_FAILED;
212
213    psb_surface->stride = luma_stride;
214
215    if (0) {
216        ;
217    } else if (512 == luma_stride) {
218        psb_surface->stride_mode = STRIDE_512;
219    } else if (1024 == luma_stride) {
220        psb_surface->stride_mode = STRIDE_1024;
221    } else if (1280 == luma_stride) {
222        psb_surface->stride_mode = STRIDE_1280;
223    } else if (2048 == luma_stride) {
224        psb_surface->stride_mode = STRIDE_2048;
225    } else if (4096 == luma_stride) {
226        psb_surface->stride_mode = STRIDE_4096;
227    } else {
228        psb_surface->stride_mode = STRIDE_NA;
229    }
230
231    psb_surface->luma_offset = luma_offset;
232    psb_surface->chroma_offset = chroma_u_offset;
233    psb_surface->size = size;
234    psb_surface->extra_info[4] = VA_FOURCC_NV12;
235    psb_surface->extra_info[8] = VA_FOURCC_NV12;
236
237    ret = psb_kbuffer_reference(driver_data, &psb_surface->buf, kbuf_handle);
238
239    return ret ? VA_STATUS_ERROR_ALLOCATION_FAILED : VA_STATUS_SUCCESS;
240}
241
242#if PSB_MFLD_DUMMY_CODE
243/* id_or_ofs: it is frame ID or frame offset in camear device memory
244 *     for CI frame: it it always frame offset currently
245 *     for v4l2 buf: it is offset used in V4L2 buffer mmap
246 */
247VAStatus psb_surface_create_camera(psb_driver_data_p driver_data,
248                                   int width, int height, int stride, int size,
249                                   psb_surface_p psb_surface, /* out */
250                                   int is_v4l2,
251                                   unsigned int id_or_ofs
252                                  )
253{
254    int ret;
255
256    if ((width <= 0) || (width > 4096) || (height <= 0) || (height > 4096)) {
257        return VA_STATUS_ERROR_ALLOCATION_FAILED;
258    }
259
260    psb_surface->stride = stride;
261    if ((width == 640) && (height == 360)) {
262        drv_debug_msg(VIDEO_DEBUG_GENERAL, "CI Frame is 640x360, and allocated as 640x368,adjust chroma_offset\n");
263        psb_surface->chroma_offset = psb_surface->stride * 368;
264    } else
265        psb_surface->chroma_offset = psb_surface->stride * height;
266    psb_surface->size = (psb_surface->stride * height * 3) / 2;
267
268    ret = psb_buffer_create_camera(driver_data, &psb_surface->buf,
269                                   is_v4l2, id_or_ofs);
270
271    if (ret != VA_STATUS_SUCCESS) {
272        psb_surface_destroy(psb_surface);
273
274        drv_debug_msg(VIDEO_DEBUG_ERROR, "Get surfae offset of camear device memory failed!\n");
275        return ret;
276    }
277
278    return VA_STATUS_SUCCESS;
279}
280
281/* id_or_ofs: it is frame ID or frame offset in camear device memory
282 *     for CI frame: it it always frame offset currently
283 *     for v4l2 buf: it is offset used in V4L2 buffer mmap
284 * user_ptr: virtual address of user buffer.
285 */
286VAStatus psb_surface_create_camera_from_ub(psb_driver_data_p driver_data,
287        int width, int height, int stride, int size,
288        psb_surface_p psb_surface, /* out */
289        int is_v4l2,
290        unsigned int id_or_ofs,
291        const unsigned long *user_ptr)
292{
293    int ret;
294
295    if ((width <= 0) || (width > 4096) || (height <= 0) || (height > 4096)) {
296        return VA_STATUS_ERROR_ALLOCATION_FAILED;
297    }
298
299    psb_surface->stride = stride;
300    psb_surface->chroma_offset = psb_surface->stride * height;
301    psb_surface->size = (psb_surface->stride * height * 3) / 2;
302
303    ret = psb_buffer_create_camera_from_ub(driver_data, &psb_surface->buf,
304                                           is_v4l2, psb_surface->size, user_ptr);
305
306    if (ret != VA_STATUS_SUCCESS) {
307        psb_surface_destroy(psb_surface);
308
309        drv_debug_msg(VIDEO_DEBUG_ERROR, "Get surfae offset of camear device memory failed!\n");
310        return ret;
311    }
312
313    return VA_STATUS_SUCCESS;
314}
315#endif
316
317/*
318 * Temporarily map surface and set all chroma values of surface to 'chroma'
319 */
320VAStatus psb_surface_set_chroma(psb_surface_p psb_surface, int chroma)
321{
322    unsigned char *surface_data;
323    int ret = psb_buffer_map(&psb_surface->buf, &surface_data);
324
325    if (ret) return VA_STATUS_ERROR_UNKNOWN;
326
327    memset(surface_data + psb_surface->chroma_offset, chroma, psb_surface->size - psb_surface->chroma_offset);
328
329    psb_buffer_unmap(&psb_surface->buf);
330
331    return VA_STATUS_SUCCESS;
332}
333
334/*
335 * Destroy surface
336 */
337void psb_surface_destroy(psb_surface_p psb_surface)
338{
339    psb_buffer_destroy(&psb_surface->buf);
340    if (NULL != psb_surface->in_loop_buf)
341        psb_buffer_destroy(psb_surface->in_loop_buf);
342
343}
344
345VAStatus psb_surface_sync(psb_surface_p psb_surface)
346{
347    wsbmBOWaitIdle(psb_surface->buf.drm_buf, 0);
348
349    return VA_STATUS_SUCCESS;
350}
351
352VAStatus psb_surface_query_status(psb_surface_p psb_surface, VASurfaceStatus *status)
353{
354    int ret;
355    uint32_t synccpu_flag = WSBM_SYNCCPU_READ | WSBM_SYNCCPU_WRITE | WSBM_SYNCCPU_DONT_BLOCK;
356
357    ret = wsbmBOSyncForCpu(psb_surface->buf.drm_buf, synccpu_flag);
358
359    if (ret == 0) {
360        (void) wsbmBOReleaseFromCpu(psb_surface->buf.drm_buf, synccpu_flag);
361        *status = VASurfaceReady;
362    } else {
363        *status = VASurfaceRendering;
364    }
365    return VA_STATUS_SUCCESS;
366}
367
368/*
369 * Set current displaying surface info to kernel
370 * so that other component can access it in another process
371 */
372int psb_surface_set_displaying(psb_driver_data_p driver_data,
373                               int width, int height,
374                               psb_surface_p psb_surface)
375{
376    struct drm_lnc_video_getparam_arg arg;
377    struct drm_video_displaying_frameinfo value;
378    int ret = 0;
379
380    if (psb_surface) {
381        value.buf_handle = (uint32_t)(wsbmKBufHandle(wsbmKBuf(psb_surface->buf.drm_buf)));
382        value.width = width;
383        value.height = height;
384        value.size = psb_surface->size;
385        value.format = psb_surface->extra_info[4];
386        value.luma_stride = psb_surface->stride;
387        value.chroma_u_stride = psb_surface->stride;
388        value.chroma_v_stride = psb_surface->stride;
389        value.luma_offset = psb_surface->luma_offset;
390        value.chroma_u_offset = psb_surface->chroma_offset;
391        value.chroma_v_offset = psb_surface->chroma_offset;
392    } else /* clean kernel displaying surface info */
393        memset(&value, 0, sizeof(value));
394
395    arg.key = IMG_VIDEO_SET_DISPLAYING_FRAME;
396    arg.value = (uint64_t)((unsigned long) & value);
397    ret = drmCommandWriteRead(driver_data->drm_fd, driver_data->getParamIoctlOffset,
398                              &arg, sizeof(arg));
399    if (ret != 0)
400        drv_debug_msg(VIDEO_DEBUG_ERROR, "IMG_VIDEO_SET_DISPLAYING_FRAME failed\n");
401
402    return ret;
403}
404