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
31#include "psb_cmdbuf.h"
32
33#include <unistd.h>
34#include <stdio.h>
35
36#include "hwdefs/mem_io.h"
37#include "hwdefs/msvdx_offsets.h"
38#include "hwdefs/dma_api.h"
39#include "hwdefs/reg_io2.h"
40#include "hwdefs/msvdx_vec_reg_io2.h"
41#include "hwdefs/msvdx_vdmc_reg_io2.h"
42#include "hwdefs/msvdx_mtx_reg_io2.h"
43#include "hwdefs/msvdx_dmac_linked_list.h"
44#include "hwdefs/msvdx_rendec_mtx_slice_cntrl_reg_io2.h"
45#include "hwdefs/dxva_cmdseq_msg.h"
46#include "hwdefs/dxva_fw_ctrl.h"
47#include "hwdefs/fwrk_msg_mem_io.h"
48#include "hwdefs/dxva_msg.h"
49#include "hwdefs/msvdx_cmds_io2.h"
50#include <stdlib.h>
51#include <errno.h>
52#include <string.h>
53#include <sys/time.h>
54
55#include "psb_def.h"
56#include "psb_drv_debug.h"
57#ifndef BAYTRAIL
58#include "psb_ws_driver.h"
59#endif
60#include <wsbm/wsbm_pool.h>
61#include <wsbm/wsbm_manager.h>
62#include <wsbm/wsbm_util.h>
63#include <wsbm/wsbm_fencemgr.h>
64
65/*
66 * Buffer layout:
67 *         cmd_base <= cmd_idx < CMD_END() == lldma_base
68 *         lldma_base <= lldma_idx < LLDMA_END() == (cmd_base + size)
69 *
70 * Reloc buffer layout:
71 *         MTX_msg < reloc_base == MTX_msg + MTXMSG_SIZE
72 *         reloc_base <= reloc_idx < RELOC_END() == (MTX_msg + reloc_size)
73 */
74#define MTXMSG_END(cmdbuf)    (cmdbuf->reloc_base)
75#define RELOC_END(cmdbuf)     (cmdbuf->MTX_msg + cmdbuf->reloc_size)
76
77#define CMD_END(cmdbuf)       (cmdbuf->lldma_base)
78#define LLDMA_END(cmdbuf)     (cmdbuf->cmd_base + cmdbuf->size)
79
80#define MTXMSG_SIZE           (0x1000)
81#define RELOC_SIZE            (0x3000)
82
83#define CMD_SIZE              (0x3000)
84#define LLDMA_SIZE            (0x2000)
85
86#define MTXMSG_MARGIN         (0x0040)
87#define RELOC_MARGIN          (0x0800)
88
89#define CMD_MARGIN            (0x0400)
90#define LLDMA_MARGIN          (0x0400)
91#define PSB_SLICE_EXTRACT_UPDATE (0x2)
92
93/*
94 * Create command buffer
95 */
96VAStatus psb_cmdbuf_create(object_context_p obj_context, psb_driver_data_p driver_data,
97                           psb_cmdbuf_p cmdbuf
98                          )
99{
100    VAStatus vaStatus = VA_STATUS_SUCCESS;
101    unsigned int size = CMD_SIZE + LLDMA_SIZE;
102    unsigned int reloc_size = MTXMSG_SIZE + RELOC_SIZE;
103    unsigned int regio_size = (obj_context->picture_width >> 4) * (obj_context->picture_height >> 4) * 172;
104
105    cmdbuf->size = 0;
106    cmdbuf->reloc_size = 0;
107    cmdbuf->regio_size = 0;
108    cmdbuf->MTX_msg = NULL;
109    cmdbuf->cmd_base = NULL;
110    cmdbuf->regio_base = NULL;
111    cmdbuf->cmd_idx = NULL;
112    cmdbuf->regio_idx = NULL;
113    cmdbuf->cmd_bitstream_size = NULL;
114    cmdbuf->lldma_base = NULL;
115    cmdbuf->lldma_idx = NULL;
116    cmdbuf->reloc_base = NULL;
117    cmdbuf->reloc_idx = NULL;
118    cmdbuf->reg_start = NULL;
119    cmdbuf->rendec_block_start = NULL;
120    cmdbuf->rendec_chunk_start = NULL;
121    cmdbuf->skip_block_start = NULL;
122    cmdbuf->last_next_segment_cmd = NULL;
123    cmdbuf->buffer_refs_count = 0;
124    cmdbuf->buffer_refs_allocated = 10;
125    cmdbuf->buffer_refs = (psb_buffer_p *) calloc(1, sizeof(psb_buffer_p) * cmdbuf->buffer_refs_allocated);
126    if (NULL == cmdbuf->buffer_refs) {
127        cmdbuf->buffer_refs_allocated = 0;
128        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
129    }
130    if (VA_STATUS_SUCCESS == vaStatus) {
131        vaStatus = psb_buffer_create(driver_data, size, psb_bt_cpu_vpu, &cmdbuf->buf);
132        cmdbuf->size = size;
133    }
134    if (VA_STATUS_SUCCESS == vaStatus) {
135        vaStatus = psb_buffer_create(driver_data, reloc_size, psb_bt_cpu_only, &cmdbuf->reloc_buf);
136        cmdbuf->reloc_size = reloc_size;
137    }
138    if (VA_STATUS_SUCCESS == vaStatus) {
139        vaStatus = psb_buffer_create(driver_data, regio_size, psb_bt_cpu_only, &cmdbuf->regio_buf);
140        cmdbuf->regio_size = regio_size;
141    }
142
143    if (VA_STATUS_SUCCESS != vaStatus) {
144        psb_cmdbuf_destroy(cmdbuf);
145    }
146    return vaStatus;
147}
148
149/*
150 * Destroy buffer
151 */
152void psb_cmdbuf_destroy(psb_cmdbuf_p cmdbuf)
153{
154    if (cmdbuf->size) {
155        psb_buffer_destroy(&cmdbuf->buf);
156        cmdbuf->size = 0;
157    }
158    if (cmdbuf->reloc_size) {
159        psb_buffer_destroy(&cmdbuf->reloc_buf);
160        cmdbuf->reloc_size = 0;
161    }
162    if (cmdbuf->regio_size) {
163        psb_buffer_destroy(&cmdbuf->regio_buf);
164        cmdbuf->regio_size = 0;
165    }
166    if (cmdbuf->buffer_refs_allocated) {
167        free(cmdbuf->buffer_refs);
168        cmdbuf->buffer_refs = NULL;
169        cmdbuf->buffer_refs_allocated = 0;
170    }
171}
172
173/*
174 * Reset buffer & map
175 *
176 * Returns 0 on success
177 */
178int psb_cmdbuf_reset(psb_cmdbuf_p cmdbuf)
179{
180    int ret;
181
182    cmdbuf->MTX_msg = NULL;
183    cmdbuf->cmd_base = NULL;
184    cmdbuf->cmd_idx = NULL;
185    cmdbuf->cmd_bitstream_size = NULL;
186    cmdbuf->lldma_base = NULL;
187    cmdbuf->lldma_idx = NULL;
188    cmdbuf->reloc_base = NULL;
189    cmdbuf->reloc_idx = NULL;
190    cmdbuf->last_next_segment_cmd = NULL;
191
192    cmdbuf->buffer_refs_count = 0;
193    cmdbuf->cmd_count = 0;
194    cmdbuf->deblock_count = 0;
195    cmdbuf->oold_count = 0;
196    cmdbuf->host_be_opp_count = 0;
197    cmdbuf->frame_info_count = 0;
198#ifdef SLICE_HEADER_PARSING
199    cmdbuf->parse_count = 0;
200#endif
201    ret = psb_buffer_map(&cmdbuf->buf, &cmdbuf->cmd_base);
202    if (ret) {
203        return ret;
204    }
205    ret = psb_buffer_map(&cmdbuf->reloc_buf, &cmdbuf->MTX_msg);
206    if (ret) {
207        psb_buffer_unmap(&cmdbuf->buf);
208        return ret;
209    }
210
211    cmdbuf->cmd_start = cmdbuf->cmd_base;
212    cmdbuf->cmd_idx = (uint32_t *) cmdbuf->cmd_base;
213    cmdbuf->cmd_bitstream_size = NULL;
214    cmdbuf->lldma_base = cmdbuf->cmd_base + CMD_SIZE;
215    cmdbuf->lldma_idx = cmdbuf->lldma_base;
216
217    cmdbuf->reloc_base = cmdbuf->MTX_msg + MTXMSG_SIZE;
218    cmdbuf->reloc_idx = (struct drm_psb_reloc *) cmdbuf->reloc_base;
219
220    /* Add ourselves to the buffer list */
221    psb_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->reloc_buf); /* reloc buf == 0 */
222    psb_cmdbuf_buffer_ref(cmdbuf, &cmdbuf->buf); /* cmd buf == 1 */
223    return ret;
224}
225
226/*
227 * Unmap buffer
228 *
229 * Returns 0 on success
230 */
231int psb_cmdbuf_unmap(psb_cmdbuf_p cmdbuf)
232{
233    cmdbuf->MTX_msg = NULL;
234    cmdbuf->cmd_base = NULL;
235    cmdbuf->cmd_start = NULL;
236    cmdbuf->cmd_idx = NULL;
237    cmdbuf->cmd_bitstream_size = NULL;
238    cmdbuf->lldma_base = NULL;
239    cmdbuf->lldma_idx = NULL;
240    cmdbuf->reloc_base = NULL;
241    cmdbuf->reloc_idx = NULL;
242    cmdbuf->cmd_count = 0;
243    psb_buffer_unmap(&cmdbuf->buf);
244    psb_buffer_unmap(&cmdbuf->reloc_buf);
245    return 0;
246}
247
248
249/*
250 * Reference an addtional buffer "buf" in the command stream
251 * Returns a reference index that can be used to refer to "buf" in
252 * relocation records, -1 on error
253 */
254int psb_cmdbuf_buffer_ref(psb_cmdbuf_p cmdbuf, psb_buffer_p buf)
255{
256    int item_loc = 0;
257
258    // buf->next = NULL; /* buf->next only used for buffer list validation */
259    while ((item_loc < cmdbuf->buffer_refs_count)
260           && (wsbmKBufHandle(wsbmKBuf(cmdbuf->buffer_refs[item_loc]->drm_buf))
261               != wsbmKBufHandle(wsbmKBuf(buf->drm_buf)))) {
262        item_loc++;
263    }
264    if (item_loc == cmdbuf->buffer_refs_count) {
265        /* Add new entry */
266        if (item_loc >= cmdbuf->buffer_refs_allocated) {
267            /* Allocate more entries */
268            int new_size = cmdbuf->buffer_refs_allocated + 10;
269            psb_buffer_p *new_array;
270            new_array = (psb_buffer_p *) calloc(1, sizeof(psb_buffer_p) * new_size);
271            if (NULL == new_array) {
272                return -1; /* Allocation failure */
273            }
274            memcpy(new_array, cmdbuf->buffer_refs, sizeof(psb_buffer_p) * cmdbuf->buffer_refs_allocated);
275            free(cmdbuf->buffer_refs);
276            cmdbuf->buffer_refs_allocated = new_size;
277            cmdbuf->buffer_refs = new_array;
278        }
279        cmdbuf->buffer_refs[item_loc] = buf;
280        cmdbuf->buffer_refs_count++;
281        buf->status = psb_bs_queued;
282
283        buf->next = NULL;
284        buf->unfence_flag = 0;
285    }
286
287    /* only for RAR buffers */
288    if ((cmdbuf->buffer_refs[item_loc] != buf)
289        && (buf->rar_handle != 0)) {
290        psb_buffer_p tmp = cmdbuf->buffer_refs[item_loc];
291        drv_debug_msg(VIDEO_DEBUG_GENERAL, "RAR: found same drm buffer with different psb buffer, link them\n",
292                                 tmp, buf);
293        while ((tmp->next != NULL)) {
294            tmp = tmp->next;
295            if (tmp == buf) /* found same buffer */
296                break;
297        }
298
299        if (tmp != buf) {
300            tmp->next = buf; /* link it */
301            buf->status = psb_bs_queued;
302            buf->next = NULL;
303        } else {
304            drv_debug_msg(VIDEO_DEBUG_GENERAL, "RAR: buffer aleady in the list, skip\n",
305                                     tmp, buf);
306        }
307    }
308
309    return item_loc;
310}
311
312/* Creates a relocation record for a DWORD in the mapped "cmdbuf" at address
313 * "addr_in_cmdbuf"
314 * The relocation is based on the device virtual address of "ref_buffer"
315 * "buf_offset" is be added to the device virtual address, and the sum is then
316 * right shifted with "align_shift".
317 * "mask" determines which bits of the target DWORD will be updated with the so
318 * constructed address. The remaining bits will be filled with bits from "background".
319 */
320void psb_cmdbuf_add_relocation(psb_cmdbuf_p cmdbuf,
321                               uint32_t *addr_in_cmdbuf,
322                               psb_buffer_p ref_buffer,
323                               uint32_t buf_offset,
324                               uint32_t mask,
325                               uint32_t background,
326                               uint32_t align_shift,
327                               uint32_t dst_buffer) /* 0 = reloc buf, 1 = cmdbuf, 2 = for host reloc */
328{
329    struct drm_psb_reloc *reloc = cmdbuf->reloc_idx;
330    uint64_t presumed_offset = wsbmBOOffsetHint(ref_buffer->drm_buf);
331
332    /* Check that address is within buffer range */
333    if (dst_buffer) {
334        ASSERT(((unsigned char *)(addr_in_cmdbuf)) >= cmdbuf->cmd_base);
335        ASSERT(((unsigned char *)(addr_in_cmdbuf)) < LLDMA_END(cmdbuf));
336        reloc->where = addr_in_cmdbuf - (uint32_t *) cmdbuf->cmd_base; /* Location in DWORDs */
337    } else {
338        ASSERT(((unsigned char *)(addr_in_cmdbuf)) >= cmdbuf->MTX_msg);
339        ASSERT(((unsigned char *)(addr_in_cmdbuf)) < MTXMSG_END(cmdbuf));
340        reloc->where = addr_in_cmdbuf - (uint32_t *) cmdbuf->MTX_msg; /* Location in DWORDs */
341    }
342
343    reloc->buffer = psb_cmdbuf_buffer_ref(cmdbuf, ref_buffer);
344    ASSERT(reloc->buffer != -1);
345
346    reloc->reloc_op = PSB_RELOC_OP_OFFSET;
347
348    psb__trace_message("[RE] Reloc at offset %08x (%08x), offset = %08x background = %08x buffer = %d (%08x)\n",
349        reloc->where, reloc->where << 2, buf_offset, background, reloc->buffer, presumed_offset);
350
351    if (presumed_offset) {
352        uint32_t new_val =  presumed_offset + buf_offset;
353        new_val = ((new_val >> align_shift) << (align_shift << PSB_RELOC_ALSHIFT_SHIFT));
354        new_val = (background & ~mask) | (new_val & mask);
355        *addr_in_cmdbuf = new_val;
356    } else {
357        *addr_in_cmdbuf = PSB_RELOC_MAGIC;
358    }
359
360    reloc->mask = mask;
361    reloc->shift = align_shift << PSB_RELOC_ALSHIFT_SHIFT;
362    reloc->pre_add =  buf_offset;
363    reloc->background = background;
364    reloc->dst_buffer = dst_buffer;
365    cmdbuf->reloc_idx++;
366
367    ASSERT(((unsigned char *)(cmdbuf->reloc_idx)) < RELOC_END(cmdbuf));
368}
369
370/*
371 * Advances "obj_context" to the next cmdbuf
372 *
373 * Returns 0 on success
374 */
375int psb_context_get_next_cmdbuf(object_context_p obj_context)
376{
377    psb_cmdbuf_p cmdbuf;
378    int ret;
379
380    if (obj_context->cmdbuf) {
381        return 0;
382    }
383
384    obj_context->cmdbuf_current++;
385    if (obj_context->cmdbuf_current >= PSB_MAX_CMDBUFS) {
386        obj_context->cmdbuf_current = 0;
387    }
388    cmdbuf = obj_context->cmdbuf_list[obj_context->cmdbuf_current];
389    ret = psb_cmdbuf_reset(cmdbuf);
390    if (!ret) {
391        /* Success */
392        obj_context->cmdbuf = cmdbuf;
393    }
394    return ret;
395}
396
397
398static unsigned
399psbTimeDiff(struct timeval *now, struct timeval *then)
400{
401    long long val;
402
403    val = now->tv_sec - then->tv_sec;
404    val *= 1000000LL;
405    val += now->tv_usec;
406    val -= then->tv_usec;
407    if (val < 1LL)
408        val = 1LL;
409
410    return (unsigned) val;
411}
412
413/*
414 * This is the user-space do-it-all interface to the drm cmdbuf ioctl.
415 * It allows different buffers as command- and reloc buffer. A list of
416 * cliprects to apply and whether to copy the clipRect content to all
417 * scanout buffers (damage = 1).
418 */
419/*
420 * Don't add debug statements in this function, it gets called with the
421 * DRM lock held and output to an X terminal can cause X to deadlock
422 */
423static int
424psbDRMCmdBuf(int fd, int ioctl_offset, psb_buffer_p *buffer_list, int buffer_count, unsigned cmdBufHandle,
425             unsigned cmdBufOffset, unsigned cmdBufSize,
426             unsigned relocBufHandle, unsigned relocBufOffset,
427             unsigned numRelocs, int __maybe_unused damage,
428             unsigned engine, unsigned fence_flags, struct psb_ttm_fence_rep *fence_arg)
429{
430    drm_psb_cmdbuf_arg_t ca;
431    struct psb_validate_arg *arg_list;
432    int i;
433    int ret;
434    struct timeval then, now;
435    Bool have_then = FALSE;
436    uint64_t mask = PSB_GPU_ACCESS_MASK;
437
438    arg_list = (struct psb_validate_arg *) calloc(1, sizeof(struct psb_validate_arg) * buffer_count);
439    if (arg_list == NULL) {
440        drv_debug_msg(VIDEO_DEBUG_ERROR, "Malloc failed \n");
441        return -ENOMEM;
442    }
443
444    for (i = 0; i < buffer_count; i++) {
445        struct psb_validate_arg *arg = &(arg_list[i]);
446        struct psb_validate_req *req = &arg->d.req;
447
448        req->next = (unsigned long) & (arg_list[i+1]);
449
450        req->buffer_handle = wsbmKBufHandle(wsbmKBuf(buffer_list[i]->drm_buf));
451        //req->group = 0;
452        req->set_flags = (PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE) & mask;
453        req->clear_flags = (~(PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE)) & mask;
454
455        req->presumed_gpu_offset = (uint64_t)wsbmBOOffsetHint(buffer_list[i]->drm_buf);
456        req->presumed_flags = PSB_USE_PRESUMED;
457        req->pad64 = (uint32_t)buffer_list[i]->pl_flags;
458#ifndef BAYTRAIL
459        req->unfence_flag = buffer_list[i]->unfence_flag;
460#endif
461    }
462    arg_list[buffer_count-1].d.req.next = 0;
463
464    ca.buffer_list = (uint64_t)((unsigned long)arg_list);
465    ca.fence_arg = (uint64_t)((unsigned long)fence_arg);
466
467    ca.cmdbuf_handle = cmdBufHandle;
468    ca.cmdbuf_offset = cmdBufOffset;
469    ca.cmdbuf_size = cmdBufSize;
470
471    ca.reloc_handle = relocBufHandle;
472    ca.reloc_offset = relocBufOffset;
473    ca.num_relocs = numRelocs;
474
475    ca.fence_flags = fence_flags;
476    ca.engine = engine;
477
478#if 0
479    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: buffer_list   = %08x\n", ca.buffer_list);
480    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: clip_rects    = %08x\n", ca.clip_rects);
481    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: cmdbuf_handle = %08x\n", ca.cmdbuf_handle);
482    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: cmdbuf_offset = %08x\n", ca.cmdbuf_offset);
483    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: cmdbuf_size   = %08x\n", ca.cmdbuf_size);
484    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: reloc_handle  = %08x\n", ca.reloc_handle);
485    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: reloc_offset  = %08x\n", ca.reloc_offset);
486    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: num_relocs    = %08x\n", ca.num_relocs);
487    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: engine        = %08x\n", ca.engine);
488    drv_debug_msg(VIDEO_DEBUG_GENERAL, "PSB submit: fence_flags   = %08x\n", ca.fence_flags);
489#endif
490
491    /*
492     * X server Signals will clobber the kernel time out mechanism.
493     * we need a user-space timeout as well.
494     */
495    do {
496        ret = drmCommandWrite(fd, ioctl_offset, &ca, sizeof(ca));
497        if (ret == EAGAIN) {
498            if (!have_then) {
499                if (gettimeofday(&then, NULL)) {
500                    drv_debug_msg(VIDEO_DEBUG_ERROR, "Gettimeofday error.\n");
501                    break;
502                }
503
504                have_then = TRUE;
505            }
506            if (gettimeofday(&now, NULL)) {
507                drv_debug_msg(VIDEO_DEBUG_ERROR, "Gettimeofday error.\n");
508                break;
509            }
510
511        }
512    } while ((ret == EAGAIN) && (psbTimeDiff(&now, &then) < PSB_TIMEOUT_USEC));
513
514    if (ret) {
515        drv_debug_msg(VIDEO_DEBUG_GENERAL, "command write return is %d\n", ret);
516        goto out;
517    }
518
519    for (i = 0; i < buffer_count; i++) {
520        struct psb_validate_arg *arg = &(arg_list[i]);
521        struct psb_validate_rep *rep = &arg->d.rep;
522
523#ifndef BAYTRAIL
524        if (arg->d.req.unfence_flag)
525            continue;
526#endif
527
528        if (!arg->handled) {
529            ret = -EFAULT;
530            goto out;
531        }
532        if (arg->ret != 0) {
533            ret = arg->ret;
534            goto out;
535        }
536        wsbmUpdateKBuf(wsbmKBuf(buffer_list[i]->drm_buf),
537                       rep->gpu_offset, rep->placement, rep->fence_type_mask);
538    }
539
540out:
541    free(arg_list);
542    for (i = 0; i < buffer_count; i++) {
543        /*
544         * Buffer no longer queued in userspace
545         */
546        psb_buffer_p tmp = buffer_list[i];
547
548        /*
549         * RAR slice buffer/surface buffer are share one BO, and then only one in
550         * buffer_list, but they are linked in psb_cmdbuf_buffer_ref
551
552         */
553        if (buffer_list[i]->rar_handle == 0)
554            tmp->next = NULL; /* don't loop for non RAR buffer, "next" may be not initialized  */
555
556        do {
557            psb_buffer_p p = tmp;
558
559            tmp = tmp->next;
560            switch (p->status) {
561            case psb_bs_queued:
562                p->status = psb_bs_ready;
563                break;
564
565            case psb_bs_abandoned:
566                psb_buffer_destroy(p);
567                free(p);
568                break;
569
570            default:
571                /* Not supposed to happen */
572                ASSERT(0);
573            }
574        } while (tmp);
575    }
576
577    return ret;
578}
579
580#if 0
581int psb_fence_destroy(struct _WsbmFenceObject *pFence)
582{
583    wsbmFenceUnreference(&pFence);
584
585    return 0;
586}
587
588struct _WsbmFenceObject *
589psb_fence_wait(psb_driver_data_p driver_data,
590               struct psb_ttm_fence_rep *fence_rep, int *status)
591
592{
593    struct _WsbmFenceObject *fence = NULL;
594    int ret = -1;
595
596    /* copy fence information */
597    if (fence_rep->error != 0) {
598        drv_debug_msg(VIDEO_DEBUG_ERROR, "drm failed to create a fence"
599                           " and has idled the HW\n");
600        DEBUG_FAILURE_RET;
601        return NULL;
602    }
603
604    fence = wsbmFenceCreate(driver_data->fence_mgr, fence_rep->fence_class,
605                            fence_rep->fence_type,
606                            (unsigned char *)fence_rep->handle,
607                            0);
608    if (fence)
609        *status = wsbmFenceFinish(fence, fence_rep->fence_type, 0);
610
611    return fence;
612}
613#endif
614
615/*
616 * Closes the last segment
617 */
618static void psb_cmdbuf_close_segment(psb_cmdbuf_p __maybe_unused cmdbuf)
619{
620#if 0
621    uint32_t bytes_used = ((unsigned char *) cmdbuf->cmd_idx - cmdbuf->cmd_start) % MTX_SEG_SIZE;
622    unsigned char *segment_start = (unsigned char *) cmdbuf->cmd_idx - bytes_used;
623    uint32_t lldma_record_offset = psb_cmdbuf_lldma_create(cmdbuf,
624                                   &(cmdbuf->buf), (segment_start - cmdbuf->cmd_base) /* offset */,
625                                   bytes_used,
626                                   0 /* destination offset */,
627                                   LLDMA_TYPE_RENDER_BUFF_MC);
628    uint32_t cmd = CMD_NEXT_SEG;
629    RELOC_SHIFT4(*cmdbuf->last_next_segment_cmd, lldma_record_offset, cmd, &(cmdbuf->buf));
630    *(cmdbuf->last_next_segment_cmd + 1) = bytes_used;
631#endif
632}
633
634/* Issue deblock cmd, HW will do deblock instead of host */
635int psb_context_submit_hw_deblock(object_context_p obj_context,
636                                  psb_buffer_p buf_a,
637                                  psb_buffer_p buf_b,
638                                  psb_buffer_p colocate_buffer,
639                                  uint32_t picture_widht_mb,
640                                  uint32_t frame_height_mb,
641                                  uint32_t rotation_flags,
642                                  uint32_t field_type,
643                                  uint32_t ext_stride_a,
644                                  uint32_t chroma_offset_a,
645                                  uint32_t chroma_offset_b,
646                                  uint32_t is_oold)
647{
648    psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
649    psb_driver_data_p driver_data = obj_context->driver_data;
650    uint32_t msg_size = FW_DEVA_DEBLOCK_SIZE;
651    unsigned int item_size = FW_DEVA_DECODE_SIZE; /* Size of a render/deocde msg */
652    FW_VA_DEBLOCK_MSG *deblock_msg;
653
654    uint32_t *msg = (uint32_t *)(cmdbuf->MTX_msg + item_size * cmdbuf->cmd_count);
655
656    memset(msg, 0, sizeof(FW_VA_DEBLOCK_MSG));
657    deblock_msg = (FW_VA_DEBLOCK_MSG *)msg;
658
659    deblock_msg->header.bits.msg_size = FW_DEVA_DEBLOCK_SIZE;
660    if (is_oold)
661        deblock_msg->header.bits.msg_type = VA_MSGID_OOLD_MFLD;
662    else
663        deblock_msg->header.bits.msg_type = VA_MSGID_DEBLOCK_MFLD;
664    deblock_msg->flags.bits.flags = FW_VA_RENDER_HOST_INT | FW_VA_RENDER_IS_LAST_SLICE | FW_DEVA_DEBLOCK_ENABLE;
665    deblock_msg->flags.bits.slice_type = field_type;
666    deblock_msg->operating_mode = obj_context->operating_mode;
667    deblock_msg->mmu_context.bits.context = (uint8_t)(obj_context->msvdx_context);
668    deblock_msg->pic_size.bits.frame_height_mb = (uint16_t)frame_height_mb;
669    deblock_msg->pic_size.bits.pic_width_mb = (uint16_t)picture_widht_mb;
670    deblock_msg->ext_stride_a = ext_stride_a;
671    deblock_msg->rotation_flags = rotation_flags;
672
673    RELOC_MSG(deblock_msg->address_a0, buf_a->buffer_ofs, buf_a);
674    RELOC_MSG(deblock_msg->address_a1, buf_a->buffer_ofs + chroma_offset_a, buf_a);
675    if (buf_b) {
676        RELOC_MSG(deblock_msg->address_b0, buf_b->buffer_ofs, buf_b);
677        RELOC_MSG(deblock_msg->address_b1, buf_b->buffer_ofs + chroma_offset_b, buf_b);
678    }
679
680    RELOC_MSG(deblock_msg->mb_param_address, colocate_buffer->buffer_ofs, colocate_buffer);
681    cmdbuf->deblock_count++;
682    return 0;
683}
684
685#ifdef PSBVIDEO_MSVDX_EC
686int psb_context_submit_host_be_opp(object_context_p obj_context,
687                                  psb_buffer_p buf_a,
688                                  psb_buffer_p buf_b,
689                                  psb_buffer_p __maybe_unused buf_c,
690                                  uint32_t picture_widht_mb,
691                                  uint32_t frame_height_mb,
692                                  uint32_t rotation_flags,
693                                  uint32_t field_type,
694                                  uint32_t ext_stride_a,
695                                  uint32_t chroma_offset_a,
696                                  uint32_t chroma_offset_b)
697{
698    psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
699    psb_driver_data_p driver_data = obj_context->driver_data;
700    uint32_t msg_size = sizeof(FW_VA_DEBLOCK_MSG);
701    unsigned int item_size = FW_DEVA_DECODE_SIZE; /* Size of a render/deocde msg */
702    FW_VA_DEBLOCK_MSG *deblock_msg;
703
704    uint32_t *msg = (uint32_t *)(cmdbuf->MTX_msg + item_size * cmdbuf->cmd_count + cmdbuf->deblock_count * msg_size);
705
706    memset(msg, 0, sizeof(FW_VA_DEBLOCK_MSG));
707    deblock_msg = (FW_VA_DEBLOCK_MSG *)msg;
708
709    deblock_msg->header.bits.msg_size = FW_DEVA_DEBLOCK_SIZE;
710    deblock_msg->header.bits.msg_type = VA_MSGID_HOST_BE_OPP_MFLD;
711    deblock_msg->flags.bits.flags = FW_VA_RENDER_HOST_INT | FW_ERROR_DETECTION_AND_RECOVERY;
712    deblock_msg->flags.bits.slice_type = field_type;
713    deblock_msg->operating_mode = obj_context->operating_mode;
714    deblock_msg->mmu_context.bits.context = (uint8_t)(obj_context->msvdx_context);
715    deblock_msg->pic_size.bits.frame_height_mb = (uint16_t)frame_height_mb;
716    deblock_msg->pic_size.bits.pic_width_mb = (uint16_t)picture_widht_mb;
717    deblock_msg->ext_stride_a = ext_stride_a;
718    deblock_msg->rotation_flags = rotation_flags;
719
720    RELOC_MSG(deblock_msg->address_a0, buf_a->buffer_ofs, buf_a);
721    RELOC_MSG(deblock_msg->address_a1, buf_a->buffer_ofs + chroma_offset_a, buf_a);
722    RELOC_MSG(deblock_msg->address_b0, buf_b->buffer_ofs, buf_b);
723    RELOC_MSG(deblock_msg->address_b1, buf_b->buffer_ofs + chroma_offset_b, buf_b);
724
725    deblock_msg->mb_param_address = wsbmKBufHandle(wsbmKBuf(buf_a->drm_buf));
726    cmdbuf->deblock_count++;
727    return 0;
728}
729#endif
730/*
731 * Submits the current cmdbuf
732 *
733 * Returns 0 on success
734 */
735int psb_context_submit_cmdbuf(object_context_p obj_context)
736{
737    psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
738    psb_driver_data_p driver_data = obj_context->driver_data;
739    unsigned int item_size = FW_DEVA_DECODE_SIZE; /* Size of a render/deocde msg */
740    int ret;
741
742
743    uint32_t cmdbuffer_size = (unsigned char *) cmdbuf->cmd_idx - cmdbuf->cmd_start; // In bytes
744
745    if (cmdbuf->last_next_segment_cmd) {
746        cmdbuffer_size = cmdbuf->first_segment_size;
747        psb_cmdbuf_close_segment(cmdbuf);
748    }
749
750    uint32_t msg_size = item_size;
751    uint32_t *msg = (uint32_t *)(cmdbuf->MTX_msg + cmdbuf->cmd_count * msg_size + cmdbuf->frame_info_count * FW_VA_FRAME_INFO_SIZE);
752
753    if (psb_video_trace_fp && (psb_video_trace_level & CMDMSG_TRACE)) {
754        debug_cmd_start[cmdbuf->cmd_count] = cmdbuf->cmd_start - cmdbuf->cmd_base;
755        debug_cmd_size[cmdbuf->cmd_count] = (unsigned char *) cmdbuf->cmd_idx - cmdbuf->cmd_start;
756        debug_cmd_count = cmdbuf->cmd_count + 1;
757    }
758
759/*
760    static int c = 0;
761    static char pFileName[30];
762
763
764    sprintf(pFileName , "cmdbuf%i.txt", c++);
765    FILE* pF = fopen(pFileName, "w");
766
767    fwrite(cmdbuf->cmd_start, 1, cmdbuffer_size, pF);
768    fclose(pF);
769*/
770    ret = psb_cmdbuf_dump((unsigned int *)cmdbuf->cmd_start, cmdbuffer_size);
771    if(ret)
772        drv_debug_msg(VIDEO_DEBUG_GENERAL, "psb_cmdbuf: dump cmdbuf fail\n");
773
774    cmdbuf->cmd_count++;
775    memset(msg, 0, msg_size);
776
777    *cmdbuf->cmd_idx = 0; // Add a trailing 0 just in case.
778    ASSERT(cmdbuffer_size < CMD_SIZE);
779    ASSERT((unsigned char *) cmdbuf->cmd_idx < CMD_END(cmdbuf));
780
781    MEMIO_WRITE_FIELD(msg, FWRK_GENMSG_SIZE,                  msg_size);
782    MEMIO_WRITE_FIELD(msg, FWRK_GENMSG_ID,                    VA_MSGID_RENDER);
783
784        MEMIO_WRITE_FIELD(msg, FW_DEVA_DECODE_CONTEXT, (obj_context->msvdx_context)); /* context is 8 bits */
785
786    /* Point to CMDBUFFER */
787    RELOC_MSG(*(msg + (FW_DEVA_DECODE_LLDMA_ADDRESS_OFFSET / sizeof(uint32_t))),
788              (cmdbuf->cmd_start - cmdbuf->cmd_base), &(cmdbuf->buf));
789    MEMIO_WRITE_FIELD(msg, FW_DEVA_DECODE_BUFFER_SIZE,          cmdbuffer_size / 4); // In dwords
790    MEMIO_WRITE_FIELD(msg, FW_DEVA_DECODE_OPERATING_MODE,       obj_context->operating_mode);
791    MEMIO_WRITE_FIELD(msg, FW_DEVA_DECODE_FLAGS,                obj_context->flags);
792
793    if (psb_video_trace_fp && (psb_video_trace_level & LLDMA_TRACE)) {
794        debug_lldma_count = (cmdbuf->lldma_idx - cmdbuf->lldma_base) / sizeof(DMA_sLinkedList);
795        debug_lldma_start = cmdbuf->lldma_base - cmdbuf->cmd_base;
796        /* Indicate last LLDMA record (for debugging) */
797        ((uint32_t *)cmdbuf->lldma_idx)[1] = 0;
798    }
799
800    cmdbuf->cmd_start = (unsigned char *)cmdbuf->cmd_idx;
801
802    if (psb_video_trace_fp) {
803        return psb_context_flush_cmdbuf(obj_context);
804    } else {
805        if ((cmdbuf->cmd_count >= MAX_CMD_COUNT) ||
806            (MTXMSG_END(cmdbuf) - (unsigned char *) msg < MTXMSG_MARGIN) ||
807            (CMD_END(cmdbuf) - (unsigned char *) cmdbuf->cmd_idx < CMD_MARGIN) ||
808            (LLDMA_END(cmdbuf) - cmdbuf->lldma_idx < LLDMA_MARGIN) ||
809            (RELOC_END(cmdbuf) - (unsigned char *) cmdbuf->reloc_idx < RELOC_MARGIN)) {
810            return psb_context_flush_cmdbuf(obj_context);
811        }
812    }
813    return 0;
814}
815
816/*
817 * Flushes all cmdbufs
818 */
819int psb_context_flush_cmdbuf(object_context_p obj_context)
820{
821    psb_cmdbuf_p cmdbuf = obj_context->cmdbuf;
822    psb_driver_data_p driver_data = obj_context->driver_data;
823    unsigned int fence_flags;
824    /* unsigned int fence_handle = 0; */
825    struct psb_ttm_fence_rep fence_rep;
826    unsigned int reloc_offset;
827    unsigned int num_relocs;
828    int ret;
829    unsigned int item_size = FW_DEVA_DECODE_SIZE; /* Size of a render/deocde msg */
830
831#ifdef SLICE_HEADER_PARSING
832    if ((NULL == cmdbuf) ||
833        (0 == (cmdbuf->cmd_count + cmdbuf->deblock_count + cmdbuf->host_be_opp_count +
834            cmdbuf->frame_info_count + cmdbuf->parse_count))) {
835        return 0; // Nothing to do
836    }
837#else
838    if ((NULL == cmdbuf) ||
839        (0 == (cmdbuf->cmd_count + cmdbuf->deblock_count + cmdbuf->host_be_opp_count + cmdbuf->frame_info_count))) {
840        return 0; // Nothing to do
841    }
842#endif
843
844    uint32_t msg_size = 0;
845    uint32_t *msg = (uint32_t *)cmdbuf->MTX_msg;
846    int32_t i;
847    uint32_t index;
848
849    /* LOCK */
850    ret = LOCK_HARDWARE(driver_data);
851    if (ret) {
852        UNLOCK_HARDWARE(driver_data);
853        DEBUG_FAILURE_RET;
854        return ret;
855    }
856
857    for (i = 1; i <= cmdbuf->frame_info_count; i++) {
858        msg_size += FW_VA_FRAME_INFO_SIZE;
859        msg += FW_VA_FRAME_INFO_SIZE / sizeof(uint32_t);
860    }
861
862    for (i = 1; i <= cmdbuf->cmd_count; i++) {
863        uint32_t flags;
864
865        flags = MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_FLAGS);
866
867        /* Update flags */
868        int bBatchEnd = (i == (cmdbuf->cmd_count + cmdbuf->deblock_count + cmdbuf->oold_count
869                               + cmdbuf->host_be_opp_count));
870        flags |=
871            (bBatchEnd ? FW_VA_RENDER_HOST_INT : FW_VA_RENDER_NO_RESPONCE_MSG);
872
873#ifdef PSBVIDEO_MSVDX_EC
874        if (driver_data->ec_enabled)
875            flags |= FW_ERROR_DETECTION_AND_RECOVERY;
876#endif
877
878        MEMIO_WRITE_FIELD(msg, FW_DEVA_DECODE_FLAGS, flags);
879
880        psb__trace_message("MSG BUFFER_SIZE       = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_BUFFER_SIZE));
881        psb__trace_message("MSG OPERATING_MODE    = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_OPERATING_MODE));
882        psb__trace_message("MSG FLAGS             = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_FLAGS));
883
884        drv_debug_msg(VIDEO_DEBUG_GENERAL, "MSG BUFFER_SIZE       = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_BUFFER_SIZE));
885        drv_debug_msg(VIDEO_DEBUG_GENERAL, "MSG OPERATING_MODE    = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_OPERATING_MODE));
886        drv_debug_msg(VIDEO_DEBUG_GENERAL, "MSG FLAGS             = %08x\n", MEMIO_READ_FIELD(msg, FW_DEVA_DECODE_FLAGS));
887
888#if 0  /* todo */
889        /* Update SAREA */
890        driver_data->psb_sarea->msvdx_context = obj_context->msvdx_context;
891#endif
892        msg += item_size / sizeof(uint32_t);
893        msg_size += item_size;
894    }
895
896    /* Assume deblock message is following render messages and no more render message behand deblock message */
897    for (i = 1; i <= cmdbuf->deblock_count; i++) {
898            msg_size += sizeof(FW_VA_DEBLOCK_MSG);
899    }
900
901    for (i = 1; i <= cmdbuf->oold_count; i++) {
902        msg_size += sizeof(FW_VA_DEBLOCK_MSG);
903    }
904
905    for (i = 1; i <= cmdbuf->host_be_opp_count; i++) {
906        msg_size += FW_VA_HOST_BE_OPP_SIZE;
907    }
908#ifdef SLICE_HEADER_PARSING
909    for (i = 1; i <= cmdbuf->parse_count; i++) {
910        msg_size += sizeof(struct fw_slice_header_extract_msg);
911    }
912#endif
913    /* Now calculate the total number of relocations */
914    reloc_offset = cmdbuf->reloc_base - cmdbuf->MTX_msg;
915    num_relocs = (((unsigned char *) cmdbuf->reloc_idx) - cmdbuf->reloc_base) / sizeof(struct drm_psb_reloc);
916
917    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Cmdbuf MTXMSG size = %08x [%08x]\n", msg_size, MTXMSG_SIZE);
918    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Cmdbuf CMD size = %08x - %d[%08x]\n", (unsigned char *) cmdbuf->cmd_idx - cmdbuf->cmd_base, cmdbuf->cmd_count, CMD_SIZE);
919    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Cmdbuf LLDMA size = %08x [%08x]\n", cmdbuf->lldma_idx - cmdbuf->lldma_base, LLDMA_SIZE);
920    drv_debug_msg(VIDEO_DEBUG_GENERAL, "Cmdbuf RELOC size = %08x [%08x]\n", num_relocs * sizeof(struct drm_psb_reloc), RELOC_SIZE);
921
922    psb_cmdbuf_unmap(cmdbuf);
923
924    psb__trace_message(NULL); /* Flush trace */
925
926    ASSERT(NULL == cmdbuf->MTX_msg);
927    ASSERT(NULL == cmdbuf->reloc_base);
928
929    if (psb_video_trace_fp)
930        fence_flags = 0;
931    else
932        fence_flags = DRM_PSB_FENCE_NO_USER;
933
934#ifdef SLICE_HEADER_PARSING
935    if (obj_context->msvdx_frame_end)
936        fence_flags |= PSB_SLICE_EXTRACT_UPDATE;
937#endif
938    /* cmdbuf will be validated as part of the buffer list */
939    /* Submit */
940    wsbmWriteLockKernelBO();
941    ret = psbDRMCmdBuf(driver_data->drm_fd, driver_data->execIoctlOffset, cmdbuf->buffer_refs,
942                       cmdbuf->buffer_refs_count,
943                       wsbmKBufHandle(wsbmKBuf(cmdbuf->reloc_buf.drm_buf)),
944                       0, msg_size,
945                       wsbmKBufHandle(wsbmKBuf(cmdbuf->reloc_buf.drm_buf)),
946                       reloc_offset, num_relocs,
947                       0, PSB_ENGINE_DECODE, fence_flags, &fence_rep);
948    wsbmWriteUnlockKernelBO();
949    UNLOCK_HARDWARE(driver_data);
950
951    if (ret) {
952        obj_context->cmdbuf = NULL;
953        obj_context->slice_count++;
954
955        DEBUG_FAILURE_RET;
956        return ret;
957    }
958
959    if (psb_video_trace_fp) {
960#if 0
961        static int error_count = 0;
962        int status = 0;
963        struct _WsbmFenceObject *fence = NULL;
964        fence = psb_fence_wait(driver_data, &fence_rep, &status);
965        drv_debug_msg(VIDEO_DEBUG_GENERAL, "psb_fence_wait returns: %d (fence=0x%08x)\n", status, fence);
966#endif
967
968        psb_buffer_map(&cmdbuf->buf, &cmdbuf->cmd_base);
969        int ret;
970        ret = psb_buffer_map(&cmdbuf->reloc_buf, &cmdbuf->MTX_msg);
971        if(ret) {
972            psb_buffer_unmap(&cmdbuf->buf);
973            return ret;
974        }
975
976        if (psb_video_trace_level & LLDMA_TRACE) {
977            psb__trace_message("lldma_count = %d, vitual=0x%08x\n",
978                               debug_lldma_count,  wsbmBOOffsetHint(cmdbuf->buf.drm_buf) + CMD_SIZE);
979            for (index = 0; index < debug_lldma_count; index++) {
980                DMA_sLinkedList* pasDmaList = (DMA_sLinkedList*)(cmdbuf->cmd_base + debug_lldma_start);
981                pasDmaList += index;
982
983                psb__trace_message("\nLLDMA record at offset %08x\n", ((unsigned char*)pasDmaList) - cmdbuf->cmd_base);
984                DW(0, BSWAP,    31, 31)
985                DW(0, DIR,    30, 30)
986                DW(0, PW,    29, 28)
987                DW(1, List_FIN, 31, 31)
988                DW(1, List_INT, 30, 30)
989                DW(1, PI,    18, 17)
990                DW(1, INCR,    16, 16)
991                DW(1, LEN,    15, 0)
992                DWH(2, ADDR,    22, 0)
993                DW(3, ACC_DEL,    31, 29)
994                DW(3, BURST,    28, 26)
995                DWH(3, EXT_SA,    3, 0)
996                DW(4, 2D_MODE,    16, 16)
997                DW(4, REP_COUNT, 10, 0)
998                DWH(5, LINE_ADD_OFF, 25, 16)
999                DW(5, ROW_LENGTH, 9, 0)
1000                DWH(6, SA, 31, 0)
1001                DWH(7, LISTPTR, 27, 0)
1002            }
1003        }
1004
1005        if (psb_video_trace_level & AUXBUF_TRACE) {
1006            psb__trace_message("debug_dump_count = %d\n", debug_dump_count);
1007            for (index = 0; index < debug_dump_count; index++) {
1008                unsigned char *buf_addr;
1009                psb__trace_message("Buffer %d = '%s' offset = %08x size = %08x\n", index, debug_dump_name[index], debug_dump_offset[index], debug_dump_size[index]);
1010                if (debug_dump_buf[index]->rar_handle
1011                    || (psb_buffer_map(debug_dump_buf[index], &buf_addr) != 0)) {
1012                    psb__trace_message("Unmappable buffer,e.g. RAR buffer\n");
1013                    continue;
1014                }
1015
1016                g_hexdump_offset = 0;
1017                psb__hexdump(buf_addr + debug_dump_offset[index], debug_dump_size[index]);
1018                psb_buffer_unmap(debug_dump_buf[index]);
1019            }
1020            debug_dump_count = 0;
1021        }
1022
1023        if (psb_video_trace_level & CMDMSG_TRACE) {
1024            psb__trace_message("cmd_count = %d, virtual=0x%08x\n",
1025                               debug_cmd_count, wsbmBOOffsetHint(cmdbuf->buf.drm_buf));
1026            for (index = 0; index < debug_cmd_count; index++) {
1027                uint32_t *msg = (uint32_t *)(cmdbuf->MTX_msg + index * item_size);
1028                uint32_t j;
1029                drv_debug_msg(VIDEO_DEBUG_GENERAL, "start = %08x size = %08x\n", debug_cmd_start[index], debug_cmd_size[index]);
1030                debug_dump_cmdbuf((uint32_t *)(cmdbuf->cmd_base + debug_cmd_start[index]), debug_cmd_size[index]);
1031
1032                for (j = 0; j < item_size / 4; j++) {
1033                    psb__trace_message("MTX msg[%d] = 0x%08x", j, *(msg + j));
1034                    switch (j) {
1035                    case 0:
1036                        psb__trace_message("[BufferSize|ID|MSG_SIZE]\n");
1037                        break;
1038                    case 1:
1039                        psb__trace_message("[MMUPTD]\n");
1040                        break;
1041                    case 2:
1042                        psb__trace_message("[LLDMA_address]\n");
1043                        break;
1044                    case 3:
1045                        psb__trace_message("[Context]\n");
1046                        break;
1047                    case 4:
1048                        psb__trace_message("[Fence_Value]\n");
1049                        break;
1050                    case 5:
1051                        psb__trace_message("[Operating_Mode]\n");
1052                        break;
1053                    case 6:
1054                        psb__trace_message("[LastMB|FirstMB]\n");
1055                        break;
1056                    case 7:
1057                        psb__trace_message("[Flags]\n");
1058                        break;
1059                    default:
1060                        psb__trace_message("[overflow]\n");
1061                        break;
1062                    }
1063                }
1064            }
1065            debug_cmd_count = 0;
1066        }
1067        psb_buffer_unmap(&cmdbuf->buf);
1068        psb_buffer_unmap(&cmdbuf->reloc_buf);
1069
1070        cmdbuf->cmd_base = NULL;
1071#if 0
1072        if (status) {
1073            drv_debug_msg(VIDEO_DEBUG_ERROR, "RENDERING ERROR FRAME=%03d SLICE=%02d status=%d\n", obj_context->frame_count, obj_context->slice_count, status);
1074            error_count++;
1075            ASSERT(status != 2);
1076            ASSERT(error_count < 40); /* Exit on 40 errors */
1077        }
1078        if (fence)
1079            psb_fence_destroy(fence);
1080#endif
1081    }
1082
1083    obj_context->cmdbuf = NULL;
1084    obj_context->slice_count++;
1085
1086    return 0;
1087}
1088
1089
1090typedef enum {
1091    MMU_GROUP0 = 0,
1092    MMU_GROUP1 = 1,
1093} MMU_GROUP;
1094
1095typedef enum    {
1096    HOST_TO_MSVDX = 0,
1097    MSXDX_TO_HOST = 1,
1098} DMA_DIRECTION;
1099
1100typedef struct {
1101    IMG_UINT32 ui32DevDestAddr ;        /* destination address */
1102    DMA_ePW     ePeripheralWidth;
1103    DMA_ePeriphIncrSize ePeriphIncrSize;
1104    DMA_ePeriphIncr     ePeriphIncr;
1105    IMG_BOOL            bSynchronous;
1106    MMU_GROUP           eMMUGroup;
1107    DMA_DIRECTION       eDMADir;
1108    DMA_eBurst          eDMA_eBurst;
1109} DMA_DETAIL_LOOKUP;
1110
1111
1112static const DMA_DETAIL_LOOKUP DmaDetailLookUp[] = {
1113    /* LLDMA_TYPE_VLC_TABLE */ {
1114        REG_MSVDX_VEC_VLC_OFFSET  ,
1115        DMA_PWIDTH_16_BIT,      /* 16 bit wide data*/
1116        DMA_PERIPH_INCR_4,      /* Incrament the dest by 32 bits */
1117        DMA_PERIPH_INCR_ON,
1118        IMG_TRUE,
1119        MMU_GROUP0,
1120        HOST_TO_MSVDX,
1121        DMA_BURST_2
1122    },
1123    /* LLDMA_TYPE_BITSTREAM */ {
1124        (REG_MSVDX_VEC_OFFSET + MSVDX_VEC_CR_VEC_SHIFTREG_STREAMIN_OFFSET),
1125        DMA_PWIDTH_8_BIT,
1126        DMA_PERIPH_INCR_1,
1127        DMA_PERIPH_INCR_OFF,
1128        IMG_FALSE,
1129        MMU_GROUP0,
1130        HOST_TO_MSVDX,
1131        DMA_BURST_4
1132    },
1133    /*LLDMA_TYPE_RESIDUAL*/             {
1134        (REG_MSVDX_VDMC_OFFSET + MSVDX_VDMC_CR_VDMC_RESIDUAL_DIRECT_INSERT_DATA_OFFSET),
1135        DMA_PWIDTH_32_BIT,
1136        DMA_PERIPH_INCR_1,
1137        DMA_PERIPH_INCR_OFF,
1138        IMG_FALSE,
1139        MMU_GROUP1,
1140        HOST_TO_MSVDX,
1141        DMA_BURST_4
1142    },
1143
1144    /*LLDMA_TYPE_RENDER_BUFF_MC*/{
1145        (REG_MSVDX_MTX_OFFSET + MTX_CORE_CR_MTX_SYSC_CDMAT_OFFSET),
1146        DMA_PWIDTH_32_BIT,
1147        DMA_PERIPH_INCR_1,
1148        DMA_PERIPH_INCR_OFF,
1149        IMG_TRUE,
1150        MMU_GROUP1,
1151        HOST_TO_MSVDX,
1152        DMA_BURST_1             /* Into MTX */
1153    },
1154    /*LLDMA_TYPE_RENDER_BUFF_VLD*/{
1155        (REG_MSVDX_MTX_OFFSET + MTX_CORE_CR_MTX_SYSC_CDMAT_OFFSET),
1156        DMA_PWIDTH_32_BIT,
1157        DMA_PERIPH_INCR_1,
1158        DMA_PERIPH_INCR_OFF,
1159        IMG_TRUE,
1160        MMU_GROUP0,
1161        HOST_TO_MSVDX,
1162        DMA_BURST_1             /* Into MTX */
1163    },
1164    /*LLDMA_TYPE_MPEG4_FESTATE_SAVE*/{
1165        (REG_MSVDX_VEC_RAM_OFFSET + 0xB90),
1166        DMA_PWIDTH_32_BIT,
1167        DMA_PERIPH_INCR_4,
1168        DMA_PERIPH_INCR_ON,
1169        IMG_TRUE,
1170        MMU_GROUP0,
1171        MSXDX_TO_HOST,
1172        DMA_BURST_2              /* From VLR */
1173    },
1174    /*LLDMA_TYPE_MPEG4_FESTATE_RESTORE*/{
1175        (REG_MSVDX_VEC_RAM_OFFSET + 0xB90),
1176        DMA_PWIDTH_32_BIT,
1177        DMA_PERIPH_INCR_4,
1178        DMA_PERIPH_INCR_ON,
1179        IMG_TRUE,
1180        MMU_GROUP0,
1181        HOST_TO_MSVDX,
1182        DMA_BURST_2             /* Into VLR */
1183    },
1184    /*LLDMA_TYPE_H264_PRELOAD_SAVE*/{
1185        (REG_MSVDX_MTX_OFFSET + MTX_CORE_CR_MTX_SYSC_CDMAT_OFFSET),
1186        DMA_PWIDTH_32_BIT,
1187        DMA_PERIPH_INCR_1,
1188        DMA_PERIPH_INCR_OFF,
1189        IMG_TRUE,       /* na */
1190        MMU_GROUP1,
1191        MSXDX_TO_HOST,
1192        DMA_BURST_1             /* From MTX */
1193    },
1194    /*LLDMA_TYPE_H264_PRELOAD_RESTORE*/{
1195        (REG_MSVDX_MTX_OFFSET + MTX_CORE_CR_MTX_SYSC_CDMAT_OFFSET),
1196        DMA_PWIDTH_32_BIT,
1197        DMA_PERIPH_INCR_1,
1198        DMA_PERIPH_INCR_OFF,
1199        IMG_TRUE,       /* na */
1200        MMU_GROUP1,
1201        HOST_TO_MSVDX,
1202        DMA_BURST_1             /* Into MTX */
1203    },
1204    /*LLDMA_TYPE_VC1_PRELOAD_SAVE*/{
1205        (REG_MSVDX_MTX_OFFSET + MTX_CORE_CR_MTX_SYSC_CDMAT_OFFSET),
1206        DMA_PWIDTH_32_BIT,
1207        DMA_PERIPH_INCR_1,
1208        DMA_PERIPH_INCR_OFF,
1209        IMG_TRUE,       /* na */
1210        MMU_GROUP0,
1211        MSXDX_TO_HOST,
1212        DMA_BURST_1             //2     /* From MTX */
1213    },
1214    /*LLDMA_TYPE_VC1_PRELOAD_RESTORE*/{
1215        (REG_MSVDX_MTX_OFFSET + MTX_CORE_CR_MTX_SYSC_CDMAT_OFFSET),
1216        DMA_PWIDTH_32_BIT,
1217        DMA_PERIPH_INCR_1,
1218        DMA_PERIPH_INCR_OFF,
1219        IMG_TRUE,       /* na */
1220        MMU_GROUP0,
1221        HOST_TO_MSVDX,
1222        DMA_BURST_1             /* Into MTX */
1223    },
1224    /*LLDMA_TYPE_MEM_SET */{
1225        (REG_MSVDX_VEC_RAM_OFFSET + 0xCC0),
1226        DMA_PWIDTH_32_BIT,
1227        DMA_PERIPH_INCR_4,
1228        DMA_PERIPH_INCR_OFF,
1229        IMG_TRUE,       /* na */
1230        MMU_GROUP0,
1231        MSXDX_TO_HOST,
1232        DMA_BURST_4                     /* From VLR */
1233    },
1234
1235};
1236
1237#define MAX_DMA_LEN     ( 0xffff )
1238
1239void *psb_cmdbuf_alloc_space(psb_cmdbuf_p cmdbuf, uint32_t byte_size)
1240{
1241    void *pos = (void *)cmdbuf->cmd_idx;
1242    ASSERT(!(byte_size % 4));
1243
1244    cmdbuf->cmd_idx += (byte_size / 4);
1245
1246    return pos;
1247}
1248
1249void psb_cmdbuf_dma_write_cmdbuf(psb_cmdbuf_p cmdbuf,
1250                                   psb_buffer_p bitstream_buf,
1251                                   uint32_t buffer_offset,
1252                                   uint32_t size,
1253                                   uint32_t dest_offset,
1254                                   DMA_TYPE type)
1255{
1256    ASSERT(size < 0xFFFF);
1257    ASSERT(buffer_offset < 0xFFFF);
1258
1259    DMA_CMD_WITH_OFFSET* dma_cmd;
1260
1261    if(dest_offset==0)
1262    {
1263            dma_cmd = (DMA_CMD_WITH_OFFSET*)psb_cmdbuf_alloc_space(cmdbuf, sizeof(DMA_CMD));
1264            dma_cmd->ui32Cmd = 0;
1265    }
1266    else
1267    {
1268            dma_cmd = (DMA_CMD_WITH_OFFSET*)psb_cmdbuf_alloc_space(cmdbuf, sizeof(DMA_CMD_WITH_OFFSET));
1269            dma_cmd->ui32Cmd = CMD_DMA_OFFSET_FLAG; // Set flag indicating that offset is deffined
1270            dma_cmd->ui32ByteOffset = dest_offset;
1271    }
1272
1273    dma_cmd->ui32Cmd |= CMD_DMA;
1274    dma_cmd->ui32Cmd |= (IMG_UINT32)type;
1275    dma_cmd->ui32Cmd |= size;
1276    /* dma_cmd->ui32DevVirtAdd  = ui32DevVirtAddress; */
1277    RELOC(dma_cmd->ui32DevVirtAdd, buffer_offset, bitstream_buf);
1278}
1279
1280/*
1281 * Write a CMD_SR_SETUP referencing a bitstream buffer to the command buffer
1282 */
1283void psb_cmdbuf_dma_write_bitstream(psb_cmdbuf_p cmdbuf,
1284                                      psb_buffer_p bitstream_buf,
1285                                      uint32_t buffer_offset,
1286                                      uint32_t size_in_bytes,
1287                                      uint32_t offset_in_bits,
1288                                      uint32_t flags)
1289{
1290    /*
1291     * We use byte alignment instead of 32bit alignment.
1292     * The third frame of sa10164.vc1 results in the following bitstream
1293     * patttern:
1294     * [0000] 00 00 03 01 76 dc 04 8d
1295     * with offset_in_bits = 0x1e
1296     * This causes an ENTDEC failure because 00 00 03 is a start code
1297     * By byte aligning the datastream the start code will be eliminated.
1298     */
1299//don't need to change the offset_in_bits, size_in_bytes and buffer_offset
1300#if 0
1301#define ALIGNMENT        sizeof(uint8_t)
1302    uint32_t bs_offset_in_dwords    = ((offset_in_bits / 8) / ALIGNMENT);
1303    size_in_bytes                   -= bs_offset_in_dwords * ALIGNMENT;
1304    offset_in_bits                  -= bs_offset_in_dwords * 8 * ALIGNMENT;
1305    buffer_offset                   += bs_offset_in_dwords * ALIGNMENT;
1306#endif
1307
1308    *cmdbuf->cmd_idx++ = CMD_SR_SETUP | flags;
1309    *cmdbuf->cmd_idx++ = offset_in_bits;
1310    cmdbuf->cmd_bitstream_size = cmdbuf->cmd_idx;
1311    *cmdbuf->cmd_idx++ = size_in_bytes;
1312    *cmdbuf->cmd_idx++ = (CMD_BITSTREAM_DMA | size_in_bytes);
1313    RELOC(*cmdbuf->cmd_idx++, buffer_offset, bitstream_buf);
1314}
1315
1316#ifdef SLICE_HEADER_PARSING
1317/*
1318 * Write a CMD_SR_SETUP referencing a bitstream buffer to the command buffer
1319 */
1320void psb_cmdbuf_dma_write_key(psb_cmdbuf_p cmdbuf,
1321                                      uint32_t flags,
1322                                      uint32_t key)
1323{
1324    drv_debug_msg(VIDEO_DEBUG_GENERAL, "pass key, flags is 0x%x, key is 0x%x.\n", flags, key);
1325    *cmdbuf->cmd_idx++ = CMD_SR_SETUP | flags;
1326    *cmdbuf->cmd_idx++ = key;
1327}
1328#endif
1329
1330/*
1331 * Chain a LLDMA bitstream command to the previous one
1332 */
1333void psb_cmdbuf_dma_write_bitstream_chained(psb_cmdbuf_p cmdbuf,
1334        psb_buffer_p bitstream_buf,
1335        uint32_t size_in_bytes)
1336{
1337    *cmdbuf->cmd_idx++ = (CMD_BITSTREAM_DMA | size_in_bytes);
1338    RELOC(*cmdbuf->cmd_idx++, bitstream_buf->buffer_ofs, bitstream_buf);
1339
1340    *(cmdbuf->cmd_bitstream_size) += size_in_bytes;
1341}
1342
1343void psb_cmdbuf_reg_start_block(psb_cmdbuf_p cmdbuf, uint32_t flags)
1344{
1345    ASSERT(NULL == cmdbuf->reg_start); /* Can't have both */
1346
1347    cmdbuf->reg_wt_p = cmdbuf->cmd_idx;
1348    cmdbuf->reg_next = 0;
1349    cmdbuf->reg_flags = (flags << 4); /* flags are diff between DE2 & DE3 */
1350    cmdbuf->reg_start = NULL;
1351}
1352
1353void psb_cmdbuf_reg_set(psb_cmdbuf_p cmdbuf, uint32_t reg, uint32_t val)
1354{
1355    if(cmdbuf->reg_start && (reg == cmdbuf->reg_next))
1356    {
1357        /* Incrament header size */
1358        *cmdbuf->reg_start += (0x1 << 16);
1359    }
1360    else
1361    {
1362        cmdbuf->reg_start = cmdbuf->reg_wt_p++;
1363        *cmdbuf->reg_start = CMD_REGVALPAIR_WRITE | cmdbuf->reg_flags | 0x10000 | (reg & 0xfffff); /* We want host reg addr */
1364    }
1365    *cmdbuf->reg_wt_p++ = val;
1366    cmdbuf->reg_next = reg + 4;
1367}
1368
1369void psb_cmdbuf_reg_set_address(psb_cmdbuf_p cmdbuf,
1370                                         uint32_t reg,
1371                                         psb_buffer_p buffer,
1372                                         uint32_t buffer_offset)
1373{
1374    if(cmdbuf->reg_start && (reg == cmdbuf->reg_next))
1375    {
1376        /* Incrament header size */
1377        *cmdbuf->reg_start += (0x1 << 16);
1378    }
1379    else
1380    {
1381        cmdbuf->reg_start = cmdbuf->reg_wt_p++;
1382        *cmdbuf->reg_start = CMD_REGVALPAIR_WRITE | cmdbuf->reg_flags | 0x10000 | (reg & 0xfffff); /* We want host reg addr */
1383    }
1384
1385    RELOC(*cmdbuf->reg_wt_p++, buffer_offset, buffer);
1386    cmdbuf->reg_next = reg + 4;
1387}
1388
1389void psb_cmdbuf_reg_end_block(psb_cmdbuf_p cmdbuf)
1390{
1391    cmdbuf->cmd_idx = cmdbuf->reg_wt_p;
1392    cmdbuf->reg_start = NULL;
1393}
1394
1395typedef enum {
1396    MTX_CTRL_HEADER = 0,
1397    RENDEC_SL_HDR,
1398    RENDEC_SL_NULL,
1399    RENDEC_CK_HDR,
1400} RENDEC_CHUNK_OFFSETS;
1401
1402/*
1403 * Start a new rendec block of another format
1404 */
1405void psb_cmdbuf_rendec_start(psb_cmdbuf_p cmdbuf, uint32_t dest_address)
1406{
1407    ASSERT(((dest_address >> 2)& ~0xfff) == 0);
1408    cmdbuf->rendec_chunk_start = cmdbuf->cmd_idx++;
1409    *cmdbuf->rendec_chunk_start = CMD_RENDEC_BLOCK | dest_address;
1410}
1411
1412void psb_cmdbuf_rendec_write_block(psb_cmdbuf_p cmdbuf,
1413                                   unsigned char *block,
1414                                   uint32_t size)
1415{
1416    ASSERT((size & 0x3) == 0);
1417    unsigned int i;
1418    for (i = 0; i < size; i += 4) {
1419        uint32_t val = block[i] | (block[i+1] << 8) | (block[i+2] << 16) | (block[i+3] << 24);
1420        psb_cmdbuf_rendec_write(cmdbuf, val);
1421    }
1422}
1423
1424void psb_cmdbuf_rendec_write_address(psb_cmdbuf_p cmdbuf,
1425                                     psb_buffer_p buffer,
1426                                     uint32_t buffer_offset)
1427{
1428    RELOC(*cmdbuf->cmd_idx++, buffer_offset, buffer);
1429}
1430
1431/*
1432 * Finish a RENDEC block
1433 */
1434void psb_cmdbuf_rendec_end(psb_cmdbuf_p cmdbuf)
1435{
1436    ASSERT(NULL != cmdbuf->rendec_chunk_start); /* Must have an open RENDEC chunk */
1437    uint32_t dword_count = cmdbuf->cmd_idx - cmdbuf->rendec_chunk_start;
1438
1439    ASSERT((dword_count - 1) <= 0xff);
1440
1441    *cmdbuf->rendec_chunk_start += ((dword_count - 1) << 16);
1442    cmdbuf->rendec_chunk_start = NULL;
1443}
1444
1445/*
1446 * Create a conditional SKIP block
1447 */
1448void psb_cmdbuf_skip_start_block(psb_cmdbuf_p cmdbuf, uint32_t skip_condition)
1449{
1450    ASSERT(NULL == cmdbuf->rendec_block_start); /* Can't be inside a rendec block */
1451    ASSERT(NULL == cmdbuf->reg_start); /* Can't be inside a reg block */
1452    ASSERT(NULL == cmdbuf->skip_block_start); /* Can't be inside another skip block (limitation of current sw design)*/
1453
1454    cmdbuf->skip_condition = skip_condition;
1455    cmdbuf->skip_block_start = cmdbuf->cmd_idx++;
1456}
1457
1458/*
1459 * Terminate a conditional SKIP block
1460 */
1461void psb_cmdbuf_skip_end_block(psb_cmdbuf_p cmdbuf)
1462{
1463    ASSERT(NULL == cmdbuf->rendec_block_start); /* Rendec block must be closed */
1464    ASSERT(NULL == cmdbuf->reg_start); /* Reg block must be closed */
1465    ASSERT(NULL != cmdbuf->skip_block_start); /* Skip block must still be open */
1466
1467    uint32_t block_size = cmdbuf->cmd_idx - (cmdbuf->skip_block_start + 1);
1468
1469    *cmdbuf->skip_block_start = CMD_CONDITIONAL_SKIP | (cmdbuf->skip_condition << 20) | block_size;
1470    cmdbuf->skip_block_start = NULL;
1471}
1472