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  *    Zeng Li <zeng.li@intel.com>
28  *    Edward Lin <edward.lin@intel.com>
29  *
30  */
31 
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <wsbm/wsbm_manager.h>
38 #include "psb_buffer.h"
39 #include "tng_cmdbuf.h"
40 #include "psb_def.h"
41 #include "psb_drv_debug.h"
42 #include "tng_hostcode.h"
43 #include "psb_ws_driver.h"
44 
45 #ifdef ANDROID
46 #include <linux/psb_drm.h>
47 #else
48 #include "psb_drm.h"
49 #endif
50 
51 #include "tng_trace.h"
52 
53 /*
54  * Buffer layout:
55  *         cmd_base <= cmd_idx < CMD_END() == reloc_base
56  *         reloc_base <= reloc_idx < RELOC_END() == (reloc_size)
57  */
58 
59 #define RELOC_END(cmdbuf)     (cmdbuf->cmd_base + cmdbuf->size)
60 #define CMD_END(cmdbuf)       (cmdbuf->reloc_base)
61 #define RELOC_SIZE            (0x3000)
62 #define CMD_SIZE              (0x3000)
63 #define RELOC_MARGIN          (0x0800)
64 #define CMD_MARGIN            (0x0400)
65 #define MAX_CMD_COUNT         12
66 #define MTX_SEG_SIZE          (0x0800)
67 
68 /*!
69  *****************************************************************************
70  *
71  * @Name           Command word format
72  *
73  * @details    Mask and shift values for command word
74  *
75  ****************************************************************************/
76 
77 /*
78  * clear buffer
79  */
tng_cmdbuf_mem_unmap(tng_cmdbuf_p cmdbuf)80 void tng_cmdbuf_mem_unmap(tng_cmdbuf_p cmdbuf)
81 {
82     psb_buffer_unmap(&cmdbuf->frame_mem);
83     psb_buffer_unmap(&cmdbuf->jpeg_pic_params);
84     psb_buffer_unmap(&cmdbuf->jpeg_header_mem);
85     psb_buffer_unmap(&cmdbuf->jpeg_header_interface_mem);
86     return ;
87 }
88 
89 /*
90  * clear buffer
91  */
tng_cmdbuf_clear(tng_cmdbuf_p cmdbuf,int flag)92 static void tng_cmdbuf_clear(tng_cmdbuf_p cmdbuf, int flag)
93 {
94     switch (flag) {
95         default:
96         case 4:
97             psb_buffer_destroy(&cmdbuf->jpeg_header_mem);
98         case 3:
99             psb_buffer_destroy(&cmdbuf->jpeg_pic_params);
100         case 2:
101         case 1:
102             psb_buffer_destroy(&cmdbuf->frame_mem);
103             break;
104     }
105 
106     if (cmdbuf->size) {
107         psb_buffer_destroy(&cmdbuf->buf);
108         cmdbuf->size = 0;
109     }
110     if (cmdbuf->buffer_refs_allocated) {
111         free(cmdbuf->buffer_refs);
112         cmdbuf->buffer_refs = NULL;
113         cmdbuf->buffer_refs_allocated = 0;
114     }
115 }
116 
117 
118 /*
119  * Create command buffer
120  */
121 
tng_cmdbuf_create(object_context_p obj_context,psb_driver_data_p driver_data,tng_cmdbuf_p cmdbuf)122 VAStatus tng_cmdbuf_create(
123     object_context_p obj_context,
124     psb_driver_data_p driver_data,
125     tng_cmdbuf_p cmdbuf)
126 {
127     context_ENC_p ctx = (context_ENC_p) obj_context->format_data;
128 
129     VAStatus vaStatus = VA_STATUS_SUCCESS;
130     unsigned int size = CMD_SIZE + RELOC_SIZE;
131 
132     cmdbuf->size = 0;
133     cmdbuf->cmd_base = NULL;
134     cmdbuf->cmd_idx = NULL;
135     cmdbuf->reloc_base = NULL;
136     cmdbuf->reloc_idx = NULL;
137     cmdbuf->buffer_refs_count = 0;
138     cmdbuf->buffer_refs_allocated = 10;
139     cmdbuf->buffer_refs = (psb_buffer_p *) calloc(1, sizeof(psb_buffer_p) * cmdbuf->buffer_refs_allocated);
140     if (NULL == cmdbuf->buffer_refs) {
141         cmdbuf->buffer_refs_allocated = 0;
142         vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
143     }
144 
145     if (VA_STATUS_SUCCESS == vaStatus) {
146         vaStatus = psb_buffer_create(driver_data, size, psb_bt_cpu_only, &cmdbuf->buf);
147         cmdbuf->size = size;
148     }
149 
150     if (VA_STATUS_SUCCESS != vaStatus) {
151         drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create 0 \n", __FUNCTION__);
152 	tng_cmdbuf_clear(cmdbuf, 1);
153         free(cmdbuf->buffer_refs);
154         cmdbuf->buffer_refs = NULL;
155         cmdbuf->buffer_refs_allocated = 0;
156         return vaStatus;
157     }
158 
159     cmdbuf->mem_size = tng_align_KB(TNG_HEADER_SIZE);
160     drv_debug_msg(VIDEO_DEBUG_GENERAL, "mem size %d\n", __FUNCTION__, cmdbuf->mem_size);
161     /* create buffer information buffer */
162     //DEBUG-FIXME
163     //tng__alloc_init_buffer(driver_data, COMM_CMD_FRAME_BUF_NUM * cmdbuf->mem_size, psb_bt_cpu_vpu, &cmdbuf->frame_mem);
164 
165     vaStatus = psb_buffer_create(driver_data, COMM_CMD_FRAME_BUF_NUM * cmdbuf->mem_size, psb_bt_cpu_vpu, &cmdbuf->frame_mem);
166     if (VA_STATUS_SUCCESS != vaStatus) {
167         drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create xx \n", __FUNCTION__);
168         free(cmdbuf->buffer_refs);
169         cmdbuf->buffer_refs = NULL;
170         cmdbuf->buffer_refs_allocated = 0;
171         return vaStatus;
172     }
173     /* all cmdbuf share one MTX_CURRENT_IN_PARAMS since every MB has a MTX_CURRENT_IN_PARAMS structure
174      * and filling this structure for all MB is very time-consuming
175      */
176 
177     /* create JPEG quantization buffer */
178     vaStatus = psb_buffer_create(driver_data, ctx->jpeg_pic_params_size, psb_bt_cpu_vpu, &cmdbuf->jpeg_pic_params);
179     if (VA_STATUS_SUCCESS != vaStatus) {
180         drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create 1 \n", __FUNCTION__);
181         tng_cmdbuf_clear(cmdbuf, 2);
182         return vaStatus;
183     }
184 
185     /* create JPEG MTX setup buffer */
186     vaStatus = psb_buffer_create(driver_data, ctx->jpeg_header_mem_size, psb_bt_cpu_vpu, &cmdbuf->jpeg_header_mem);
187     if (VA_STATUS_SUCCESS != vaStatus) {
188         drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create 2 \n", __FUNCTION__);
189         tng_cmdbuf_clear(cmdbuf, 3);
190         return vaStatus;
191     }
192 
193     /* create JPEG MTX setup interface buffer */
194     vaStatus = psb_buffer_create(driver_data, ctx->jpeg_header_interface_mem_size, psb_bt_cpu_vpu, &cmdbuf->jpeg_header_interface_mem);
195     if (VA_STATUS_SUCCESS != vaStatus) {
196         drv_debug_msg(VIDEO_DEBUG_ERROR, "psb buffer create 3 \n", __FUNCTION__);
197         tng_cmdbuf_clear(cmdbuf, 4);
198         return vaStatus;
199     }
200 
201     return vaStatus;
202 }
203 
204 /*
205  * Destroy buffer
206  */
tng_cmdbuf_destroy(tng_cmdbuf_p cmdbuf)207 void tng_cmdbuf_destroy(tng_cmdbuf_p cmdbuf)
208 {
209     psb_buffer_destroy(&cmdbuf->frame_mem);
210     psb_buffer_destroy(&cmdbuf->jpeg_header_mem);
211     psb_buffer_destroy(&cmdbuf->jpeg_pic_params);
212     psb_buffer_destroy(&cmdbuf->jpeg_header_interface_mem);
213 
214     if (cmdbuf->size) {
215         psb_buffer_destroy(&cmdbuf->buf);
216         cmdbuf->size = 0;
217     }
218     if (cmdbuf->buffer_refs_allocated) {
219         free(cmdbuf->buffer_refs);
220         cmdbuf->buffer_refs = NULL;
221         cmdbuf->buffer_refs_allocated = 0;
222     }
223     return ;
224 }
225 
226 /*
227  * Reset buffer & map
228  *
229  * Returns 0 on success
230  */
tng_cmdbuf_reset(tng_cmdbuf_p cmdbuf)231 int tng_cmdbuf_reset(tng_cmdbuf_p cmdbuf)
232 {
233     int ret;
234     cmdbuf->cmd_base = NULL;
235     cmdbuf->cmd_idx = NULL;
236     cmdbuf->reloc_base = NULL;
237     cmdbuf->reloc_idx = NULL;
238 
239     cmdbuf->buffer_refs_count = 0;
240     cmdbuf->frame_mem_index = 0;
241     cmdbuf->cmd_count = 0;
242     cmdbuf->mem_size = tng_align_KB(TNG_HEADER_SIZE);
243 
244     ret = psb_buffer_map(&cmdbuf->buf, &cmdbuf->cmd_base);
245     if (ret) {
246         return ret;
247     }
248 
249     cmdbuf->cmd_start = cmdbuf->cmd_base;
250     cmdbuf->cmd_idx = (IMG_UINT32 *) cmdbuf->cmd_base;
251 
252     cmdbuf->reloc_base = cmdbuf->cmd_base + CMD_SIZE;
253     cmdbuf->reloc_idx = (struct drm_psb_reloc *) cmdbuf->reloc_base;
254 
255     /* Add ourselves to the buffer list */
256     tng_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->buf); /* cmd buf == 0 */
257     return ret;
258 }
259 
260 /*
261  * Unmap buffer
262  *
263  * Returns 0 on success
264  */
tng_cmdbuf_unmap(tng_cmdbuf_p cmdbuf)265 int tng_cmdbuf_unmap(tng_cmdbuf_p cmdbuf)
266 {
267     cmdbuf->cmd_base = NULL;
268     cmdbuf->cmd_start = NULL;
269     cmdbuf->cmd_idx = NULL;
270     cmdbuf->reloc_base = NULL;
271     cmdbuf->reloc_idx = NULL;
272     cmdbuf->cmd_count = 0;
273     psb_buffer_unmap(&cmdbuf->buf);
274     return 0;
275 }
276 
277 
278 /*
279  * Reference an addtional buffer "buf" in the command stream
280  * Returns a reference index that can be used to refer to "buf" in
281  * relocation records, -1 on error
282  */
tng_cmdbuf_buffer_ref(tng_cmdbuf_p cmdbuf,psb_buffer_p buf)283 int tng_cmdbuf_buffer_ref(tng_cmdbuf_p cmdbuf, psb_buffer_p buf)
284 {
285     int item_loc = 0;
286 
287     /*Reserve the same TTM BO twice will cause kernel lock up*/
288     while ((item_loc < cmdbuf->buffer_refs_count)
289            && (wsbmKBufHandle(wsbmKBuf(cmdbuf->buffer_refs[item_loc]->drm_buf))
290                != wsbmKBufHandle(wsbmKBuf(buf->drm_buf))))
291         //while( (item_loc < cmdbuf->buffer_refs_count) && (cmdbuf->buffer_refs[item_loc] != buf) )
292     {
293         item_loc++;
294     }
295     if (item_loc == cmdbuf->buffer_refs_count) {
296         /* Add new entry */
297         if (item_loc >= cmdbuf->buffer_refs_allocated) {
298             /* Allocate more entries */
299             int new_size = cmdbuf->buffer_refs_allocated + 10;
300             psb_buffer_p *new_array;
301             new_array = (psb_buffer_p *) calloc(1, sizeof(psb_buffer_p) * new_size);
302             if (NULL == new_array) {
303                 return -1; /* Allocation failure */
304             }
305             memcpy(new_array, cmdbuf->buffer_refs, sizeof(psb_buffer_p) * cmdbuf->buffer_refs_allocated);
306             free(cmdbuf->buffer_refs);
307             cmdbuf->buffer_refs_allocated = new_size;
308             cmdbuf->buffer_refs = new_array;
309         }
310         cmdbuf->buffer_refs[item_loc] = buf;
311         cmdbuf->buffer_refs_count++;
312         buf->status = psb_bs_queued;
313     }
314     return item_loc;
315 }
316 
317 /* Creates a relocation record for a DWORD in the mapped "cmdbuf" at address
318  * "addr_in_cmdbuf"
319  * The relocation is based on the device virtual address of "ref_buffer"
320  * "buf_offset" is be added to the device virtual address, and the sum is then
321  * right shifted with "align_shift".
322  * "mask" determines which bits of the target DWORD will be updated with the so
323  * constructed address. The remaining bits will be filled with bits from "background".
324  */
tng_cmdbuf_add_relocation(tng_cmdbuf_p cmdbuf,IMG_UINT32 * addr_in_dst_buffer,psb_buffer_p ref_buffer,IMG_UINT32 buf_offset,IMG_UINT32 mask,IMG_UINT32 background,IMG_UINT32 align_shift,IMG_UINT32 dst_buffer,IMG_UINT32 * start_of_dst_buffer)325 void tng_cmdbuf_add_relocation(tng_cmdbuf_p cmdbuf,
326                                IMG_UINT32 *addr_in_dst_buffer,/*addr of dst_buffer for the DWORD*/
327                                psb_buffer_p ref_buffer,
328                                IMG_UINT32 buf_offset,
329                                IMG_UINT32 mask,
330                                IMG_UINT32 background,
331                                IMG_UINT32 align_shift,
332                                IMG_UINT32 dst_buffer,
333                                IMG_UINT32 *start_of_dst_buffer) /*Index of the list refered by cmdbuf->buffer_refs */
334 {
335     struct drm_psb_reloc *reloc = cmdbuf->reloc_idx;
336     uint64_t presumed_offset = wsbmBOOffsetHint(ref_buffer->drm_buf);
337 
338     reloc->where = addr_in_dst_buffer - start_of_dst_buffer; /* Offset in DWORDs */
339 
340     reloc->buffer = tng_cmdbuf_buffer_ref(cmdbuf, ref_buffer);
341     ASSERT(reloc->buffer != -1);
342 
343     reloc->reloc_op = PSB_RELOC_OP_OFFSET;
344 #ifndef VA_EMULATOR
345     if (presumed_offset) {
346         IMG_UINT32 new_val =  presumed_offset + buf_offset;
347 
348         new_val = ((new_val >> align_shift) << (align_shift << PSB_RELOC_ALSHIFT_SHIFT));
349         new_val = (background & ~mask) | (new_val & mask);
350         *addr_in_dst_buffer = new_val;
351     } else {
352         *addr_in_dst_buffer = PSB_RELOC_MAGIC;
353     }
354 #else
355     /* indicate subscript of relocation buffer */
356     *addr_in_dst_buffer = reloc - (struct drm_psb_reloc *)cmdbuf->reloc_base;
357 #endif
358     reloc->mask = mask;
359     reloc->shift = align_shift << PSB_RELOC_ALSHIFT_SHIFT;
360     reloc->pre_add = buf_offset;
361     reloc->background = background;
362     reloc->dst_buffer = dst_buffer;
363     cmdbuf->reloc_idx++;
364 
365     ASSERT(((void *)(cmdbuf->reloc_idx)) < RELOC_END(cmdbuf));
366 }
367 
368 /* Prepare one command package */
tng_cmdbuf_insert_command(object_context_p obj_context,IMG_UINT32 stream_id,IMG_UINT32 cmd_id,IMG_UINT32 cmd_data,psb_buffer_p data_addr,IMG_UINT32 offset)369 void tng_cmdbuf_insert_command(
370     object_context_p obj_context,
371     IMG_UINT32 stream_id,
372     IMG_UINT32 cmd_id,
373     IMG_UINT32 cmd_data,
374     psb_buffer_p data_addr,
375     IMG_UINT32 offset)
376 {
377     IMG_UINT32 cmd_word;
378     context_ENC_p ctx = (context_ENC_p) obj_context->format_data;
379     context_ENC_cmdbuf *ps_cmd = &(ctx->ctx_cmdbuf[stream_id]);
380     context_ENC_mem *ps_mem = &(ctx->ctx_mem[stream_id]);
381     tng_cmdbuf_p cmdbuf = obj_context->tng_cmdbuf;
382     psb_driver_data_p driver_data = ctx->obj_context->driver_data;
383     int interrupt_flags;
384 
385     //CMD composed by user space does not generate Interrupt
386     interrupt_flags = 0;
387 
388     assert(stream_id <= TOPAZHP_MAX_NUM_STREAMS);
389 
390     /* Write command to FIFO */
391     {
392         cmd_word = F_ENCODE(stream_id, MTX_MSG_CORE) |
393             F_ENCODE(cmd_id, MTX_MSG_CMD_ID);
394 
395         if (cmd_id & MTX_CMDID_PRIORITY) {
396             /* increment the command counter */
397             ps_cmd->ui32HighCmdCount++;
398 
399             /* Prepare high priority command */
400             cmd_word |= F_ENCODE(1, MTX_MSG_PRIORITY) |
401                 F_ENCODE(((ps_cmd->ui32LowCmdCount - 1) & 0xff) |(ps_cmd->ui32HighCmdCount << 8), MTX_MSG_COUNT);
402         } else {
403             /* Prepare low priority command */
404             cmd_word |=
405             F_ENCODE(ps_cmd->ui32LowCmdCount & 0xff, MTX_MSG_COUNT);
406             ++(ps_cmd->ui32LowCmdCount);
407         }
408         drv_debug_msg(VIDEO_DEBUG_GENERAL,
409             "%s: cmd_id = 0x%08x\n",
410             __FUNCTION__, cmd_word);
411         *cmdbuf->cmd_idx++ = cmd_word;
412     }
413 
414     /* write command word into cmdbuf */
415     *cmdbuf->cmd_idx++ = cmd_data;
416 /* Command data address */
417     if (data_addr) {
418         if (cmd_id == MTX_CMDID_RC_UPDATE) {
419             *cmdbuf->cmd_idx++ = (IMG_UINT32)data_addr;
420             drv_debug_msg(VIDEO_DEBUG_GENERAL,
421                         "%s: data_addr = 0x%08x\n",
422                         __FUNCTION__, *(cmdbuf->cmd_idx));
423         } else {
424             if ((cmd_id >= MTX_CMDID_SETQUANT) && (cmd_id <= MTX_CMDID_SETUP)) {
425                 if (cmd_id == MTX_CMDID_ISSUEBUFF)
426                     TNG_RELOC_CMDBUF_START(cmdbuf->cmd_idx, offset, data_addr);
427                 else
428                     tng_cmdbuf_set_phys(cmdbuf->cmd_idx, 0, data_addr, offset, 0);
429             } else {
430 #ifdef _TNG_RELOC_
431                 TNG_RELOC_CMDBUF_START(cmdbuf->cmd_idx, offset, data_addr);
432 #else
433                 tng_cmdbuf_set_phys(cmdbuf->cmd_idx, 0, data_addr, offset, 0);
434 #endif
435             }
436             drv_debug_msg(VIDEO_DEBUG_GENERAL,
437                 "%s: data_addr = 0x%08x\n",
438                 __FUNCTION__, *(cmdbuf->cmd_idx));
439             cmdbuf->cmd_idx++;
440         }
441     } else {
442         *cmdbuf->cmd_idx++ = 0;
443     }
444 
445     if (cmd_id == MTX_CMDID_SW_FILL_INPUT_CTRL) {
446         *cmdbuf->cmd_idx++ = ctx->ui16IntraRefresh;
447         *cmdbuf->cmd_idx++ = ctx->sRCParams.ui32InitialQp;
448         *cmdbuf->cmd_idx++ = ctx->sRCParams.iMinQP;
449         *cmdbuf->cmd_idx++ = ctx->ctx_mem_size.mb_ctrl_in_params;
450         *cmdbuf->cmd_idx++ = ctx->ui32pseudo_rand_seed;
451     }
452 
453     if (cmd_id == MTX_CMDID_SW_UPDATE_AIR_SEND) {
454         *cmdbuf->cmd_idx++ = ctx->sAirInfo.i16AIRSkipCnt;
455         *cmdbuf->cmd_idx++ = ctx->sAirInfo.i32NumAIRSPerFrame;
456         *cmdbuf->cmd_idx++ = ctx->ctx_mem_size.mb_ctrl_in_params;
457         *cmdbuf->cmd_idx++ = ctx->ui32FrameCount[0];
458     }
459 
460     if (cmd_id == MTX_CMDID_SW_UPDATE_AIR_CALC) {
461         *cmdbuf->cmd_idx++ = ctx->ctx_mem_size.first_pass_out_best_multipass_param;
462         *cmdbuf->cmd_idx++ = ctx->sAirInfo.i32SAD_Threshold;
463         *cmdbuf->cmd_idx++ = ctx->ui8EnableSelStatsFlags;
464     }
465 
466     /* Command data address */
467     if (cmd_id == MTX_CMDID_SETVIDEO) {
468         *(cmdbuf->cmd_idx)++ = wsbmKBufHandle(wsbmKBuf(ctx->bufs_writeback.drm_buf));
469         drv_debug_msg(VIDEO_DEBUG_GENERAL,
470             "%s: cmd_param = 0x%08x\n",
471             __FUNCTION__, *(cmdbuf->cmd_idx - 1));
472 
473     if (data_addr)
474         *(cmdbuf->cmd_idx)++ = wsbmKBufHandle(wsbmKBuf(data_addr->drm_buf));
475 
476         *(cmdbuf->cmd_idx)++ = wsbmKBufHandle(wsbmKBuf(ps_mem->bufs_mb_ctrl_in_params.drm_buf));
477         *(cmdbuf->cmd_idx)++ =  wsbmKBufHandle(wsbmKBuf(ps_mem->bufs_first_pass_out_params.drm_buf));
478         *(cmdbuf->cmd_idx)++ =  wsbmKBufHandle(wsbmKBuf(ps_mem->bufs_first_pass_out_best_multipass_param.drm_buf));
479     }
480 
481     if (cmd_id == MTX_CMDID_SETUP_INTERFACE) {
482         *(cmdbuf->cmd_idx)++ = wsbmKBufHandle(wsbmKBuf(ctx->bufs_writeback.drm_buf));
483         drv_debug_msg(VIDEO_DEBUG_GENERAL,
484             "%s: cmd_param = 0x%08x\n",
485             __FUNCTION__, *(cmdbuf->cmd_idx - 1));
486     }
487 
488     if (cmd_id == MTX_CMDID_SHUTDOWN) {
489         *(cmdbuf->cmd_idx)++ = ctx->eCodec;
490 
491         drv_debug_msg(VIDEO_DEBUG_GENERAL,
492             "%s: cmd_param = 0x%08x\n",
493             __FUNCTION__, *(cmdbuf->cmd_idx - 1));
494     }
495 
496     return ;
497 }
498 
499 
500 /*
501  * Advances "obj_context" to the next cmdbuf
502  *
503  * Returns 0 on success
504  */
tng_context_get_next_cmdbuf(object_context_p obj_context)505 int tng_context_get_next_cmdbuf(object_context_p obj_context)
506 {
507     tng_cmdbuf_p cmdbuf;
508     int ret;
509 
510     drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: start obj_context->tng_cmdbuf = %x\n", __FUNCTION__, obj_context->tng_cmdbuf);
511 
512     if (obj_context->tng_cmdbuf) {
513         return 0;
514     }
515 
516     obj_context->cmdbuf_current++;
517     if (obj_context->cmdbuf_current >= TNG_MAX_CMDBUFS_ENCODE) {
518         obj_context->cmdbuf_current = 0;
519     }
520 
521     cmdbuf = obj_context->tng_cmdbuf_list[obj_context->cmdbuf_current];
522     ret = tng_cmdbuf_reset(cmdbuf);
523     if (!ret) {
524         /* Success */
525         obj_context->tng_cmdbuf = cmdbuf;
526     }
527 
528 //    tng_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->pic_params);
529 //    tng_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->slice_mem);
530     return ret;
531 }
532 
533 /*
534  * This is the user-space do-it-all interface to the drm cmdbuf ioctl.
535  * It allows different buffers as command- and reloc buffer. A list of
536  * cliprects to apply and whether to copy the clipRect content to all
537  * scanout buffers (damage = 1).
538  */
539 /*
540  * Don't add debug statements in this function, it gets called with the
541  * DRM lock held and output to an X terminal can cause X to deadlock
542  */
543 static int
ptgDRMCmdBuf(int fd,int ioctl_offset,psb_buffer_p * buffer_list,int buffer_count,unsigned cmdBufHandle,unsigned cmdBufOffset,unsigned cmdBufSize,unsigned relocBufHandle,unsigned relocBufOffset,unsigned numRelocs,int __maybe_unused damage,unsigned engine,unsigned fence_flags,struct psb_ttm_fence_rep * fence_rep)544 ptgDRMCmdBuf(int fd, int ioctl_offset, psb_buffer_p *buffer_list, int buffer_count, unsigned cmdBufHandle,
545              unsigned cmdBufOffset, unsigned cmdBufSize,
546              unsigned relocBufHandle, unsigned relocBufOffset,
547              unsigned numRelocs, int __maybe_unused damage,
548              unsigned engine, unsigned fence_flags, struct psb_ttm_fence_rep *fence_rep)
549 {
550     drm_psb_cmdbuf_arg_t ca;
551     struct psb_validate_arg *arg_list;
552     int i, ret;
553     unsigned int retry = 0;
554     uint64_t mask = PSB_GPU_ACCESS_MASK;
555 
556     arg_list = (struct psb_validate_arg *) calloc(1, sizeof(struct psb_validate_arg) * buffer_count);
557     if (arg_list == NULL) {
558         drv_debug_msg(VIDEO_DEBUG_ERROR, "Allocate memory failed\n");
559         return -ENOMEM;
560     }
561 
562     for (i = 0; i < buffer_count; i++) {
563         struct psb_validate_arg *arg = &(arg_list[i]);
564         struct psb_validate_req *req = &arg->d.req;
565 
566         //memset(arg, 0, sizeof(*arg));
567         req->next = (unsigned long) & (arg_list[i+1]);
568 
569         req->buffer_handle = wsbmKBufHandle(wsbmKBuf(buffer_list[i]->drm_buf));
570         //req->group = 0;
571         req->set_flags = (PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE) & mask;
572         req->clear_flags = (~(PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE)) & mask;
573 #if 1
574         req->presumed_gpu_offset = (uint64_t)wsbmBOOffsetHint(buffer_list[i]->drm_buf);
575         req->presumed_flags = PSB_USE_PRESUMED;
576 #else
577         req->presumed_flags = 0;
578 #endif
579         req->pad64 = (IMG_UINT32)buffer_list[i]->pl_flags;
580 #ifndef BAYTRAIL
581         req->unfence_flag = buffer_list[i]->unfence_flag;
582 #endif
583     }
584     arg_list[buffer_count-1].d.req.next = 0;
585 
586     memset(&ca, 0, sizeof(ca));
587 
588     ca.buffer_list = (uint64_t)((unsigned long)arg_list);
589     ca.cmdbuf_handle = cmdBufHandle;
590     ca.cmdbuf_offset = cmdBufOffset;
591     ca.cmdbuf_size = cmdBufSize;
592     ca.reloc_handle = relocBufHandle;
593     ca.reloc_offset = relocBufOffset;
594     ca.num_relocs = numRelocs;
595     ca.engine = engine;
596     ca.fence_flags = fence_flags;
597     ca.fence_arg = (uint64_t)((unsigned long)fence_rep);
598     //ca.damage = damage;
599 
600 
601     do {
602         ret = drmCommandWrite(fd, ioctl_offset, &ca, sizeof(ca));
603         if (ret == -EAGAIN || ret == -EBUSY) {
604             drv_debug_msg(VIDEO_DEBUG_ERROR, "drmCommandWrite returns with %s, retry\n",
605                           ret==-EAGAIN?"EAGAIN":"EBUSY");
606             retry++;
607         }
608     } while (ret == -EAGAIN || ret == -EBUSY);
609 
610     if (retry > 0)
611         drv_debug_msg(VIDEO_DEBUG_ERROR,"drmCommandWrite tries %d time, finally %s with ret=%d\n",
612                       retry, ret==0?"okay":"failed!", ret);
613 
614     if (ret)
615         goto out;
616 
617     for (i = 0; i < buffer_count; i++) {
618         struct psb_validate_arg *arg = &(arg_list[i]);
619         struct psb_validate_rep *rep = &arg->d.rep;
620 
621         if (!arg->handled) {
622             ret = -EFAULT;
623             goto out;
624         }
625         if (arg->ret != 0) {
626             ret = arg->ret;
627             goto out;
628         }
629         wsbmUpdateKBuf(wsbmKBuf(buffer_list[i]->drm_buf),
630                        rep->gpu_offset, rep->placement, rep->fence_type_mask);
631     }
632 out:
633     free(arg_list);
634     for (i = 0; i < buffer_count; i++) {
635         /*
636          * Buffer no longer queued in userspace
637          */
638         switch (buffer_list[i]->status) {
639         case psb_bs_queued:
640             buffer_list[i]->status = psb_bs_ready;
641             break;
642 
643         case psb_bs_abandoned:
644             psb_buffer_destroy(buffer_list[i]);
645             free(buffer_list[i]);
646             break;
647 
648         default:
649             /* Not supposed to happen */
650             ASSERT(0);
651         }
652     }
653 
654     return ret;
655 }
656 
657 #if 0
658 static struct _WsbmFenceObject *
659 lnc_fence_wait(psb_driver_data_p driver_data,
660                struct psb_ttm_fence_rep *fence_rep, int *status)
661 
662 {
663     struct _WsbmFenceObject *fence = NULL;
664     int ret = -1;
665 
666     /* copy fence information */
667     if (fence_rep->error != 0) {
668         drv_debug_msg(VIDEO_DEBUG_ERROR, "drm failed to create a fence"
669                            " and has idled the HW\n");
670         DEBUG_FAILURE_RET;
671         return NULL;
672     }
673 
674     fence = wsbmFenceCreate(driver_data->fence_mgr, fence_rep->fence_class,
675                             fence_rep->fence_type,
676                             (void *)fence_rep->handle,
677                             0);
678     if (fence)
679         *status = wsbmFenceFinish(fence, fence_rep->fence_type, 0);
680 
681     return fence;
682 }
683 #endif
684 
685 /*
686  * Submits the current cmdbuf
687  *
688  * Returns 0 on success
689  */
tng_context_submit_cmdbuf(object_context_p __maybe_unused obj_context)690 int tng_context_submit_cmdbuf(object_context_p __maybe_unused obj_context)
691 {
692     return 0;
693 }
694 
695 
696 
697 /*
698  * FrameSkip is only meaningful for RC enabled mode
699  * Topaz raises this flag after surface N encoding is finished (vaSyncSurface gets back)
700  * then for the next encode surface N+1 (ctx->src_surface) frameskip flag is cleared in vaBeginPicuture
701  * and is always set in vaEndPicture:lnc_PatchRCMode
702  * vaQuerySurfaceStatus is supposed only to be called after vaEndPicture/vaSyncSurface,
703  * The caller should ensure the surface pertains to an encode context
704  */
tng_surface_get_frameskip(psb_driver_data_p __maybe_unused driver_data,psb_surface_p surface,int * frame_skip)705 int tng_surface_get_frameskip(psb_driver_data_p __maybe_unused driver_data,
706                               psb_surface_p surface,
707                               int *frame_skip)
708 {
709     /* bit31 indicate if frameskip is already settled, it is used to record the frame skip flag for old surfaces
710      * bit31 is cleared when the surface is used as encode render target or reference/reconstrucure target
711      */
712     if (GET_SURFACE_INFO_skipped_flag(surface) & SURFACE_INFO_SKIP_FLAG_SETTLED) {
713         *frame_skip = GET_SURFACE_INFO_skipped_flag(surface) & 1;
714     } else
715         *frame_skip = 0;
716 
717     return 0;
718 }
719 
tng_set_frame_skip_flag(object_context_p obj_context)720 VAStatus tng_set_frame_skip_flag(object_context_p obj_context)
721 {
722     VAStatus vaStatus = VA_STATUS_SUCCESS;
723     context_ENC_p ctx = (context_ENC_p) obj_context->format_data;
724     context_ENC_frame_buf *ps_buf = &(ctx->ctx_frame_buf);
725 
726     if (ctx && ps_buf->previous_src_surface) {
727         SET_SURFACE_INFO_skipped_flag(ps_buf->previous_src_surface->psb_surface, 1);
728         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Detected a skipped frame for surface 0x%08x.\n",
729             ps_buf->previous_src_surface->psb_surface);
730     }
731 
732     return vaStatus;
733 }
734 
735 
736 /*
737  * Flushes all cmdbufs
738  */
tng_context_flush_cmdbuf(object_context_p obj_context)739 int tng_context_flush_cmdbuf(object_context_p obj_context)
740 {
741     tng_cmdbuf_p cmdbuf = obj_context->tng_cmdbuf;
742     psb_driver_data_p driver_data = obj_context->driver_data;
743     unsigned int fence_flags;
744     struct psb_ttm_fence_rep fence_rep;
745     unsigned int reloc_offset;
746     unsigned int num_relocs;
747     int ret;
748     unsigned int cmdbuffer_size = (unsigned int) (((unsigned char *)(cmdbuf->cmd_idx)) - cmdbuf->cmd_start); /* In bytes */
749 
750     ASSERT(cmdbuffer_size < CMD_SIZE);
751     ASSERT((void *) cmdbuf->cmd_idx < CMD_END(cmdbuf));
752     /* LOCK */
753     ret = LOCK_HARDWARE(driver_data);
754     if (ret) {
755         UNLOCK_HARDWARE(driver_data);
756         DEBUG_FAILURE_RET;
757         return ret;
758     }
759 
760     /* Now calculate the total number of relocations */
761     reloc_offset = cmdbuf->reloc_base - cmdbuf->cmd_base;
762     num_relocs = (((unsigned char *) (cmdbuf->reloc_idx)) - cmdbuf->reloc_base) / sizeof(struct drm_psb_reloc);
763 
764     tng_cmdbuf_unmap(cmdbuf);
765 
766     ASSERT(NULL == cmdbuf->reloc_base);
767 
768 #ifdef DEBUG_TRACE
769     fence_flags = 0;
770 #else
771     fence_flags = DRM_PSB_FENCE_NO_USER;
772 #endif
773 
774 
775     wsbmWriteLockKernelBO();
776 #if 1 //_PO_DEBUG_
777     ret = ptgDRMCmdBuf(driver_data->drm_fd, driver_data->execIoctlOffset, /* FIXME Still use ioctl cmd? */
778                        cmdbuf->buffer_refs, cmdbuf->buffer_refs_count, wsbmKBufHandle(wsbmKBuf(cmdbuf->buf.drm_buf)),
779                        0, cmdbuffer_size,/*unsigned cmdBufSize*/
780                        wsbmKBufHandle(wsbmKBuf(cmdbuf->buf.drm_buf)), reloc_offset, num_relocs,
781                        0, LNC_ENGINE_ENCODE, fence_flags, &fence_rep); /* FIXME use LNC_ENGINE_ENCODE */
782 #endif
783     wsbmWriteUnlockKernelBO();
784 
785     UNLOCK_HARDWARE(driver_data);
786 
787     if (ret) {
788         obj_context->tng_cmdbuf = NULL;
789 
790         DEBUG_FAILURE_RET;
791         return ret;
792     }
793 
794 #if 0 /*DEBUG_TRACE*/
795     int status = -1;
796     struct _WsbmFenceObject *fence = NULL;
797 
798     fence = lnc_fence_wait(driver_data, &fence_rep, &status);
799     drv_debug_msg(VIDEO_DEBUG_GENERAL, "psb_fence_wait returns: %d (fence=0x%08x)\n", status, fence);
800 
801     if (fence)
802         wsbmFenceUnreference(fence);
803 #endif
804 
805     obj_context->tng_cmdbuf = NULL;
806 
807     return 0;
808 }
809 
810 
tng_cmdbuf_set_phys(IMG_UINT32 * dest_buf,int dest_num,psb_buffer_p ref_buf,unsigned int ref_ofs,unsigned int ref_len)811 void tng_cmdbuf_set_phys(IMG_UINT32 *dest_buf, int dest_num,
812     psb_buffer_p ref_buf, unsigned int ref_ofs, unsigned int ref_len)
813 {
814     int i = 0;
815     IMG_UINT32 addr_phys = (IMG_UINT32)wsbmBOOffsetHint(ref_buf->drm_buf) + ref_ofs;
816 
817 //    drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s: drm_buf 0x%08x, addr_phys 0x%08x, virt addr 0x%08x\n", __FUNCTION__, ref_buf->drm_buf, addr_phys, ref_buf->virtual_addr );
818 
819     do {
820         dest_buf[i] =  addr_phys;
821         ++i;
822         addr_phys += ref_len;
823     } while(i < dest_num);
824     return ;
825 }
826 
827 
tng_get_pipe_number(object_context_p obj_context)828 int tng_get_pipe_number(object_context_p obj_context)
829 {
830 
831     context_ENC_p ctx = (context_ENC_p)(obj_context->format_data);
832     return ctx->ui8PipesToUse;
833 
834 }
835 
836