media: mediatek: vcodec: Fix h264 set lat buffer error
[platform/kernel/linux-starfive.git] / drivers / media / platform / mediatek / vcodec / vdec / vdec_h264_req_multi_if.c
index 4cc9270..955b2d0 100644 (file)
@@ -471,14 +471,19 @@ static int vdec_h264_slice_core_decode(struct vdec_lat_buf *lat_buf)
               sizeof(share_info->h264_slice_params));
 
        fb = ctx->dev->vdec_pdata->get_cap_buffer(ctx);
-       y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0;
-       vdec_fb_va = (unsigned long)fb;
+       if (!fb) {
+               err = -EBUSY;
+               mtk_vcodec_err(inst, "fb buffer is NULL");
+               goto vdec_dec_end;
+       }
 
+       vdec_fb_va = (unsigned long)fb;
+       y_fb_dma = (u64)fb->base_y.dma_addr;
        if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 1)
                c_fb_dma =
                        y_fb_dma + inst->ctx->picinfo.buf_w * inst->ctx->picinfo.buf_h;
        else
-               c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0;
+               c_fb_dma = (u64)fb->base_c.dma_addr;
 
        mtk_vcodec_debug(inst, "[h264-core] y/c addr = 0x%llx 0x%llx", y_fb_dma,
                         c_fb_dma);
@@ -539,6 +544,29 @@ vdec_dec_end:
        return 0;
 }
 
+static void vdec_h264_insert_startcode(struct mtk_vcodec_dev *vcodec_dev, unsigned char *buf,
+                                      size_t *bs_size, struct mtk_h264_pps_param *pps)
+{
+       struct device *dev = &vcodec_dev->plat_dev->dev;
+
+       /* Need to add pending data at the end of bitstream when bs_sz is small than
+        * 20 bytes for cavlc bitstream, or lat will decode fail. This pending data is
+        * useful for mt8192 and mt8195 platform.
+        *
+        * cavlc bitstream when entropy_coding_mode_flag is false.
+        */
+       if (pps->entropy_coding_mode_flag || *bs_size > 20 ||
+           !(of_device_is_compatible(dev->of_node, "mediatek,mt8192-vcodec-dec") ||
+           of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-dec")))
+               return;
+
+       buf[*bs_size] = 0;
+       buf[*bs_size + 1] = 0;
+       buf[*bs_size + 2] = 1;
+       buf[*bs_size + 3] = 0xff;
+       (*bs_size) += 4;
+}
+
 static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
                                      struct vdec_fb *fb, bool *res_chg)
 {
@@ -582,9 +610,6 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
        }
 
        inst->vsi->dec.nal_info = buf[nal_start_idx];
-       inst->vsi->dec.bs_buf_addr = (u64)bs->dma_addr;
-       inst->vsi->dec.bs_buf_size = bs->size;
-
        lat_buf->src_buf_req = src_buf_info->m2m_buf.vb.vb2_buf.req_obj.req;
        v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, &lat_buf->ts_info, true);
 
@@ -592,6 +617,12 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
        if (err)
                goto err_free_fb_out;
 
+       vdec_h264_insert_startcode(inst->ctx->dev, buf, &bs->size,
+                                  &share_info->h264_slice_params.pps);
+
+       inst->vsi->dec.bs_buf_addr = (uint64_t)bs->dma_addr;
+       inst->vsi->dec.bs_buf_size = bs->size;
+
        *res_chg = inst->resolution_changed;
        if (inst->resolution_changed) {
                mtk_vcodec_debug(inst, "- resolution changed -");
@@ -630,7 +661,7 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
        err = vpu_dec_start(vpu, data, 2);
        if (err) {
                mtk_vcodec_debug(inst, "lat decode err: %d", err);
-               goto err_scp_decode;
+               goto err_free_fb_out;
        }
 
        share_info->trans_end = inst->ctx->msg_queue.wdma_addr.dma_addr +
@@ -647,12 +678,17 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
        /* wait decoder done interrupt */
        timeout = mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED,
                                               WAIT_INTR_TIMEOUT_MS, MTK_VDEC_LAT0);
+       if (timeout)
+               mtk_vcodec_err(inst, "lat decode timeout: pic_%d", inst->slice_dec_num);
        inst->vsi->dec.timeout = !!timeout;
 
        err = vpu_dec_end(vpu);
-       if (err == SLICE_HEADER_FULL || timeout || err == TRANS_BUFFER_FULL) {
-               err = -EINVAL;
-               goto err_scp_decode;
+       if (err == SLICE_HEADER_FULL || err == TRANS_BUFFER_FULL) {
+               if (!IS_VDEC_INNER_RACING(inst->ctx->dev->dec_capability))
+                       vdec_msg_queue_qbuf(&inst->ctx->msg_queue.lat_ctx, lat_buf);
+               inst->slice_dec_num++;
+               mtk_vcodec_err(inst, "lat dec fail: pic_%d err:%d", inst->slice_dec_num, err);
+               return -EINVAL;
        }
 
        share_info->trans_end = inst->ctx->msg_queue.wdma_addr.dma_addr +
@@ -669,10 +705,6 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
 
        inst->slice_dec_num++;
        return 0;
-
-err_scp_decode:
-       if (!IS_VDEC_INNER_RACING(inst->ctx->dev->dec_capability))
-               vdec_msg_queue_qbuf(&inst->ctx->msg_queue.lat_ctx, lat_buf);
 err_free_fb_out:
        vdec_msg_queue_qbuf(&inst->ctx->msg_queue.lat_ctx, lat_buf);
        mtk_vcodec_err(inst, "slice dec number: %d err: %d", inst->slice_dec_num, err);