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  */
psb_surface_create(psb_driver_data_p driver_data,int width,int height,int fourcc,unsigned int flags,psb_surface_p psb_surface)39 VAStatus 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 
psb_surface_create_for_userptr(psb_driver_data_p driver_data,int width,int height,unsigned size,unsigned int __maybe_unused fourcc,unsigned int luma_stride,unsigned int __maybe_unused chroma_u_stride,unsigned int __maybe_unused chroma_v_stride,unsigned int luma_offset,unsigned int chroma_u_offset,unsigned int __maybe_unused chroma_v_offset,psb_surface_p psb_surface)159 VAStatus 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 
psb_surface_create_from_kbuf(psb_driver_data_p driver_data,int width,int height,unsigned size,unsigned int __maybe_unused fourcc,int __maybe_unused kbuf_handle,unsigned int luma_stride,unsigned int __maybe_unused chroma_u_stride,unsigned int __maybe_unused chroma_v_stride,unsigned int __maybe_unused luma_offset,unsigned int chroma_u_offset,unsigned int __maybe_unused chroma_v_offset,psb_surface_p psb_surface)193 VAStatus 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  */
psb_surface_create_camera(psb_driver_data_p driver_data,int width,int height,int stride,int size,psb_surface_p psb_surface,int is_v4l2,unsigned int id_or_ofs)247 VAStatus 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  */
psb_surface_create_camera_from_ub(psb_driver_data_p driver_data,int width,int height,int stride,int size,psb_surface_p psb_surface,int is_v4l2,unsigned int id_or_ofs,const unsigned long * user_ptr)286 VAStatus 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  */
psb_surface_set_chroma(psb_surface_p psb_surface,int chroma)320 VAStatus 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  */
psb_surface_destroy(psb_surface_p psb_surface)337 void 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 
psb_surface_sync(psb_surface_p psb_surface)345 VAStatus 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 
psb_surface_query_status(psb_surface_p psb_surface,VASurfaceStatus * status)352 VAStatus 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  */
psb_surface_set_displaying(psb_driver_data_p driver_data,int width,int height,psb_surface_p psb_surface)372 int 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