Home | History | Annotate | Download | only in src
      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 (at) intel.com>
     27  *    Zeng Li <zeng.li (at) intel.com>
     28  *    Edward Lin <edward.lin (at) 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  */
     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  */
     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 
    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  */
    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  */
    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  */
    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  */
    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  */
    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 */
    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  */
    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
    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  */
    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  */
    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 
    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  */
    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 
    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 
    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