162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NVIDIA Tegra Video decoder driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2016-2022 Dmitry Osipenko <digetx@gmail.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/iopoll.h> 1062306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1162306a36Sopenharmony_ci#include <linux/reset.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <media/v4l2-h264.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "trace.h" 1762306a36Sopenharmony_ci#include "vde.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define FLAG_B_FRAME 0x1 2062306a36Sopenharmony_ci#define FLAG_REFERENCE 0x2 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct tegra_vde_h264_frame { 2362306a36Sopenharmony_ci unsigned int frame_num; 2462306a36Sopenharmony_ci unsigned int flags; 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistruct tegra_vde_h264_decoder_ctx { 2862306a36Sopenharmony_ci unsigned int dpb_frames_nb; 2962306a36Sopenharmony_ci unsigned int dpb_ref_frames_with_earlier_poc_nb; 3062306a36Sopenharmony_ci unsigned int baseline_profile; 3162306a36Sopenharmony_ci unsigned int level_idc; 3262306a36Sopenharmony_ci unsigned int log2_max_pic_order_cnt_lsb; 3362306a36Sopenharmony_ci unsigned int log2_max_frame_num; 3462306a36Sopenharmony_ci unsigned int pic_order_cnt_type; 3562306a36Sopenharmony_ci unsigned int direct_8x8_inference_flag; 3662306a36Sopenharmony_ci unsigned int pic_width_in_mbs; 3762306a36Sopenharmony_ci unsigned int pic_height_in_mbs; 3862306a36Sopenharmony_ci unsigned int pic_init_qp; 3962306a36Sopenharmony_ci unsigned int deblocking_filter_control_present_flag; 4062306a36Sopenharmony_ci unsigned int constrained_intra_pred_flag; 4162306a36Sopenharmony_ci unsigned int chroma_qp_index_offset; 4262306a36Sopenharmony_ci unsigned int pic_order_present_flag; 4362306a36Sopenharmony_ci unsigned int num_ref_idx_l0_active_minus1; 4462306a36Sopenharmony_ci unsigned int num_ref_idx_l1_active_minus1; 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct h264_reflists { 4862306a36Sopenharmony_ci struct v4l2_h264_reference p[V4L2_H264_NUM_DPB_ENTRIES]; 4962306a36Sopenharmony_ci struct v4l2_h264_reference b0[V4L2_H264_NUM_DPB_ENTRIES]; 5062306a36Sopenharmony_ci struct v4l2_h264_reference b1[V4L2_H264_NUM_DPB_ENTRIES]; 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int tegra_vde_wait_mbe(struct tegra_vde *vde) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci u32 tmp; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci return readl_relaxed_poll_timeout(vde->mbe + 0x8C, tmp, 5862306a36Sopenharmony_ci tmp >= 0x10, 1, 100); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int tegra_vde_setup_mbe_frame_idx(struct tegra_vde *vde, 6262306a36Sopenharmony_ci unsigned int refs_nb, 6362306a36Sopenharmony_ci bool setup_refs) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci u32 value, frame_idx_enb_mask = 0; 6662306a36Sopenharmony_ci unsigned int frame_idx; 6762306a36Sopenharmony_ci unsigned int idx; 6862306a36Sopenharmony_ci int err; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci tegra_vde_writel(vde, 0xD0000000 | (0 << 23), vde->mbe, 0x80); 7162306a36Sopenharmony_ci tegra_vde_writel(vde, 0xD0200000 | (0 << 23), vde->mbe, 0x80); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci err = tegra_vde_wait_mbe(vde); 7462306a36Sopenharmony_ci if (err) 7562306a36Sopenharmony_ci return err; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (!setup_refs) 7862306a36Sopenharmony_ci return 0; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci for (idx = 0, frame_idx = 1; idx < refs_nb; idx++, frame_idx++) { 8162306a36Sopenharmony_ci tegra_vde_writel(vde, 0xD0000000 | (frame_idx << 23), 8262306a36Sopenharmony_ci vde->mbe, 0x80); 8362306a36Sopenharmony_ci tegra_vde_writel(vde, 0xD0200000 | (frame_idx << 23), 8462306a36Sopenharmony_ci vde->mbe, 0x80); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci frame_idx_enb_mask |= frame_idx << (6 * (idx % 4)); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (idx % 4 == 3 || idx == refs_nb - 1) { 8962306a36Sopenharmony_ci value = 0xC0000000; 9062306a36Sopenharmony_ci value |= (idx >> 2) << 24; 9162306a36Sopenharmony_ci value |= frame_idx_enb_mask; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci tegra_vde_writel(vde, value, vde->mbe, 0x80); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci err = tegra_vde_wait_mbe(vde); 9662306a36Sopenharmony_ci if (err) 9762306a36Sopenharmony_ci return err; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci frame_idx_enb_mask = 0; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic void tegra_vde_mbe_set_0xa_reg(struct tegra_vde *vde, int reg, u32 val) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci tegra_vde_writel(vde, 0xA0000000 | (reg << 24) | (val & 0xFFFF), 10962306a36Sopenharmony_ci vde->mbe, 0x80); 11062306a36Sopenharmony_ci tegra_vde_writel(vde, 0xA0000000 | ((reg + 1) << 24) | (val >> 16), 11162306a36Sopenharmony_ci vde->mbe, 0x80); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int tegra_vde_wait_bsev(struct tegra_vde *vde, bool wait_dma) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct device *dev = vde->dev; 11762306a36Sopenharmony_ci u32 value; 11862306a36Sopenharmony_ci int err; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, 12162306a36Sopenharmony_ci !(value & BIT(2)), 1, 100); 12262306a36Sopenharmony_ci if (err) { 12362306a36Sopenharmony_ci dev_err(dev, "BSEV unknown bit timeout\n"); 12462306a36Sopenharmony_ci return err; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, 12862306a36Sopenharmony_ci (value & BSE_ICMDQUE_EMPTY), 1, 100); 12962306a36Sopenharmony_ci if (err) { 13062306a36Sopenharmony_ci dev_err(dev, "BSEV ICMDQUE flush timeout\n"); 13162306a36Sopenharmony_ci return err; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (!wait_dma) 13562306a36Sopenharmony_ci return 0; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, 13862306a36Sopenharmony_ci !(value & BSE_DMA_BUSY), 1, 1000); 13962306a36Sopenharmony_ci if (err) { 14062306a36Sopenharmony_ci dev_err(dev, "BSEV DMA timeout\n"); 14162306a36Sopenharmony_ci return err; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int tegra_vde_push_to_bsev_icmdqueue(struct tegra_vde *vde, 14862306a36Sopenharmony_ci u32 value, bool wait_dma) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci tegra_vde_writel(vde, value, vde->bsev, ICMDQUE_WR); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return tegra_vde_wait_bsev(vde, wait_dma); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic void tegra_vde_setup_frameid(struct tegra_vde *vde, 15662306a36Sopenharmony_ci struct tegra_video_frame *frame, 15762306a36Sopenharmony_ci unsigned int frameid, 15862306a36Sopenharmony_ci u32 mbs_width, u32 mbs_height) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci u32 y_addr = frame ? frame->y_addr : 0x6CDEAD00; 16162306a36Sopenharmony_ci u32 cb_addr = frame ? frame->cb_addr : 0x6CDEAD00; 16262306a36Sopenharmony_ci u32 cr_addr = frame ? frame->cr_addr : 0x6CDEAD00; 16362306a36Sopenharmony_ci u32 value1 = frame ? ((frame->luma_atoms_pitch << 16) | mbs_height) : 0; 16462306a36Sopenharmony_ci u32 value2 = frame ? ((frame->chroma_atoms_pitch << 6) | 1) : 0; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci tegra_vde_writel(vde, y_addr >> 8, vde->frameid, 0x000 + frameid * 4); 16762306a36Sopenharmony_ci tegra_vde_writel(vde, cb_addr >> 8, vde->frameid, 0x100 + frameid * 4); 16862306a36Sopenharmony_ci tegra_vde_writel(vde, cr_addr >> 8, vde->frameid, 0x180 + frameid * 4); 16962306a36Sopenharmony_ci tegra_vde_writel(vde, value1, vde->frameid, 0x080 + frameid * 4); 17062306a36Sopenharmony_ci tegra_vde_writel(vde, value2, vde->frameid, 0x280 + frameid * 4); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic void tegra_setup_frameidx(struct tegra_vde *vde, 17462306a36Sopenharmony_ci struct tegra_video_frame *frames, 17562306a36Sopenharmony_ci unsigned int frames_nb, 17662306a36Sopenharmony_ci u32 mbs_width, u32 mbs_height) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci unsigned int idx; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci for (idx = 0; idx < frames_nb; idx++) 18162306a36Sopenharmony_ci tegra_vde_setup_frameid(vde, &frames[idx], idx, 18262306a36Sopenharmony_ci mbs_width, mbs_height); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci for (; idx < 17; idx++) 18562306a36Sopenharmony_ci tegra_vde_setup_frameid(vde, NULL, idx, 0, 0); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic void tegra_vde_setup_iram_entry(struct tegra_vde *vde, 18962306a36Sopenharmony_ci unsigned int table, 19062306a36Sopenharmony_ci unsigned int row, 19162306a36Sopenharmony_ci u32 value1, u32 value2) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci u32 *iram_tables = vde->iram; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci trace_vde_setup_iram_entry(table, row, value1, value2); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci iram_tables[0x20 * table + row * 2 + 0] = value1; 19862306a36Sopenharmony_ci iram_tables[0x20 * table + row * 2 + 1] = value2; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic void tegra_vde_setup_iram_tables(struct tegra_vde *vde, 20262306a36Sopenharmony_ci struct tegra_video_frame *dpb_frames, 20362306a36Sopenharmony_ci unsigned int ref_frames_nb, 20462306a36Sopenharmony_ci unsigned int with_earlier_poc_nb) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct tegra_video_frame *frame; 20762306a36Sopenharmony_ci int with_later_poc_nb; 20862306a36Sopenharmony_ci u32 value, aux_addr; 20962306a36Sopenharmony_ci unsigned int i, k; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci trace_vde_ref_l0(dpb_frames[0].frame_num); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci for (i = 0; i < 16; i++) { 21462306a36Sopenharmony_ci if (i < ref_frames_nb) { 21562306a36Sopenharmony_ci frame = &dpb_frames[i + 1]; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci aux_addr = frame->aux_addr; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci value = (i + 1) << 26; 22062306a36Sopenharmony_ci value |= !(frame->flags & FLAG_B_FRAME) << 25; 22162306a36Sopenharmony_ci value |= 1 << 24; 22262306a36Sopenharmony_ci value |= frame->frame_num; 22362306a36Sopenharmony_ci } else { 22462306a36Sopenharmony_ci aux_addr = 0x6ADEAD00; 22562306a36Sopenharmony_ci value = 0x3f; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci tegra_vde_setup_iram_entry(vde, 0, i, value, aux_addr); 22962306a36Sopenharmony_ci tegra_vde_setup_iram_entry(vde, 1, i, value, aux_addr); 23062306a36Sopenharmony_ci tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); 23162306a36Sopenharmony_ci tegra_vde_setup_iram_entry(vde, 3, i, value, aux_addr); 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (!(dpb_frames[0].flags & FLAG_B_FRAME)) 23562306a36Sopenharmony_ci return; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (with_earlier_poc_nb >= ref_frames_nb) 23862306a36Sopenharmony_ci return; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci with_later_poc_nb = ref_frames_nb - with_earlier_poc_nb; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci trace_vde_ref_l1(with_later_poc_nb, with_earlier_poc_nb); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci for (i = 0, k = with_earlier_poc_nb; i < with_later_poc_nb; i++, k++) { 24562306a36Sopenharmony_ci frame = &dpb_frames[k + 1]; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci aux_addr = frame->aux_addr; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci value = (k + 1) << 26; 25062306a36Sopenharmony_ci value |= !(frame->flags & FLAG_B_FRAME) << 25; 25162306a36Sopenharmony_ci value |= 1 << 24; 25262306a36Sopenharmony_ci value |= frame->frame_num; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci for (k = 0; i < ref_frames_nb; i++, k++) { 25862306a36Sopenharmony_ci frame = &dpb_frames[k + 1]; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci aux_addr = frame->aux_addr; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci value = (k + 1) << 26; 26362306a36Sopenharmony_ci value |= !(frame->flags & FLAG_B_FRAME) << 25; 26462306a36Sopenharmony_ci value |= 1 << 24; 26562306a36Sopenharmony_ci value |= frame->frame_num; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int tegra_vde_setup_hw_context(struct tegra_vde *vde, 27262306a36Sopenharmony_ci struct tegra_vde_h264_decoder_ctx *ctx, 27362306a36Sopenharmony_ci struct tegra_video_frame *dpb_frames, 27462306a36Sopenharmony_ci dma_addr_t bitstream_data_addr, 27562306a36Sopenharmony_ci size_t bitstream_data_size, 27662306a36Sopenharmony_ci unsigned int macroblocks_nb) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct device *dev = vde->dev; 27962306a36Sopenharmony_ci u32 value; 28062306a36Sopenharmony_ci int err; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci tegra_vde_set_bits(vde, 0x000A, vde->sxe, 0xF0); 28362306a36Sopenharmony_ci tegra_vde_set_bits(vde, 0x000B, vde->bsev, CMDQUE_CONTROL); 28462306a36Sopenharmony_ci tegra_vde_set_bits(vde, 0x8002, vde->mbe, 0x50); 28562306a36Sopenharmony_ci tegra_vde_set_bits(vde, 0x000A, vde->mbe, 0xA0); 28662306a36Sopenharmony_ci tegra_vde_set_bits(vde, 0x000A, vde->ppe, 0x14); 28762306a36Sopenharmony_ci tegra_vde_set_bits(vde, 0x000A, vde->ppe, 0x28); 28862306a36Sopenharmony_ci tegra_vde_set_bits(vde, 0x0A00, vde->mce, 0x08); 28962306a36Sopenharmony_ci tegra_vde_set_bits(vde, 0x000A, vde->tfe, 0x00); 29062306a36Sopenharmony_ci tegra_vde_set_bits(vde, 0x0005, vde->vdma, 0x04); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci tegra_vde_writel(vde, 0x00000000, vde->vdma, 0x1C); 29362306a36Sopenharmony_ci tegra_vde_writel(vde, 0x00000000, vde->vdma, 0x00); 29462306a36Sopenharmony_ci tegra_vde_writel(vde, 0x00000007, vde->vdma, 0x04); 29562306a36Sopenharmony_ci tegra_vde_writel(vde, 0x00000007, vde->frameid, 0x200); 29662306a36Sopenharmony_ci tegra_vde_writel(vde, 0x00000005, vde->tfe, 0x04); 29762306a36Sopenharmony_ci tegra_vde_writel(vde, 0x00000000, vde->mbe, 0x84); 29862306a36Sopenharmony_ci tegra_vde_writel(vde, 0x00000010, vde->sxe, 0x08); 29962306a36Sopenharmony_ci tegra_vde_writel(vde, 0x00000150, vde->sxe, 0x54); 30062306a36Sopenharmony_ci tegra_vde_writel(vde, 0x0000054C, vde->sxe, 0x58); 30162306a36Sopenharmony_ci tegra_vde_writel(vde, 0x00000E34, vde->sxe, 0x5C); 30262306a36Sopenharmony_ci tegra_vde_writel(vde, 0x063C063C, vde->mce, 0x10); 30362306a36Sopenharmony_ci tegra_vde_writel(vde, 0x0003FC00, vde->bsev, INTR_STATUS); 30462306a36Sopenharmony_ci tegra_vde_writel(vde, 0x0000150D, vde->bsev, BSE_CONFIG); 30562306a36Sopenharmony_ci tegra_vde_writel(vde, 0x00000100, vde->bsev, BSE_INT_ENB); 30662306a36Sopenharmony_ci tegra_vde_writel(vde, 0x00000000, vde->bsev, 0x98); 30762306a36Sopenharmony_ci tegra_vde_writel(vde, 0x00000060, vde->bsev, 0x9C); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci memset(vde->iram + 128, 0, macroblocks_nb / 2); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci tegra_setup_frameidx(vde, dpb_frames, ctx->dpb_frames_nb, 31262306a36Sopenharmony_ci ctx->pic_width_in_mbs, ctx->pic_height_in_mbs); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci tegra_vde_setup_iram_tables(vde, dpb_frames, 31562306a36Sopenharmony_ci ctx->dpb_frames_nb - 1, 31662306a36Sopenharmony_ci ctx->dpb_ref_frames_with_earlier_poc_nb); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* 31962306a36Sopenharmony_ci * The IRAM mapping is write-combine, ensure that CPU buffers have 32062306a36Sopenharmony_ci * been flushed at this point. 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci wmb(); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci tegra_vde_writel(vde, 0x00000000, vde->bsev, 0x8C); 32562306a36Sopenharmony_ci tegra_vde_writel(vde, bitstream_data_addr + bitstream_data_size, 32662306a36Sopenharmony_ci vde->bsev, 0x54); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci vde->bitstream_data_addr = bitstream_data_addr; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci value = ctx->pic_width_in_mbs << 11 | ctx->pic_height_in_mbs << 3; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci tegra_vde_writel(vde, value, vde->bsev, 0x88); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci err = tegra_vde_wait_bsev(vde, false); 33562306a36Sopenharmony_ci if (err) 33662306a36Sopenharmony_ci return err; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x800003FC, false); 33962306a36Sopenharmony_ci if (err) 34062306a36Sopenharmony_ci return err; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci value = 0x01500000; 34362306a36Sopenharmony_ci value |= ((vde->iram_lists_addr + 512) >> 2) & 0xFFFF; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci err = tegra_vde_push_to_bsev_icmdqueue(vde, value, true); 34662306a36Sopenharmony_ci if (err) 34762306a36Sopenharmony_ci return err; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x840F054C, false); 35062306a36Sopenharmony_ci if (err) 35162306a36Sopenharmony_ci return err; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x80000080, false); 35462306a36Sopenharmony_ci if (err) 35562306a36Sopenharmony_ci return err; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci value = 0x0E340000 | ((vde->iram_lists_addr >> 2) & 0xFFFF); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci err = tegra_vde_push_to_bsev_icmdqueue(vde, value, true); 36062306a36Sopenharmony_ci if (err) 36162306a36Sopenharmony_ci return err; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci value = 0x00800005; 36462306a36Sopenharmony_ci value |= ctx->pic_width_in_mbs << 11; 36562306a36Sopenharmony_ci value |= ctx->pic_height_in_mbs << 3; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci tegra_vde_writel(vde, value, vde->sxe, 0x10); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci value = !ctx->baseline_profile << 17; 37062306a36Sopenharmony_ci value |= ctx->level_idc << 13; 37162306a36Sopenharmony_ci value |= ctx->log2_max_pic_order_cnt_lsb << 7; 37262306a36Sopenharmony_ci value |= ctx->pic_order_cnt_type << 5; 37362306a36Sopenharmony_ci value |= ctx->log2_max_frame_num; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci tegra_vde_writel(vde, value, vde->sxe, 0x40); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci value = ctx->pic_init_qp << 25; 37862306a36Sopenharmony_ci value |= !!(ctx->deblocking_filter_control_present_flag) << 2; 37962306a36Sopenharmony_ci value |= !!ctx->pic_order_present_flag; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci tegra_vde_writel(vde, value, vde->sxe, 0x44); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci value = ctx->chroma_qp_index_offset; 38462306a36Sopenharmony_ci value |= ctx->num_ref_idx_l0_active_minus1 << 5; 38562306a36Sopenharmony_ci value |= ctx->num_ref_idx_l1_active_minus1 << 10; 38662306a36Sopenharmony_ci value |= !!ctx->constrained_intra_pred_flag << 15; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci tegra_vde_writel(vde, value, vde->sxe, 0x48); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci value = 0x0C000000; 39162306a36Sopenharmony_ci value |= !!(dpb_frames[0].flags & FLAG_B_FRAME) << 24; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci tegra_vde_writel(vde, value, vde->sxe, 0x4C); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci value = 0x03800000; 39662306a36Sopenharmony_ci value |= bitstream_data_size & GENMASK(19, 15); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci tegra_vde_writel(vde, value, vde->sxe, 0x68); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci tegra_vde_writel(vde, bitstream_data_addr, vde->sxe, 0x6C); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (vde->soc->supports_ref_pic_marking) 40362306a36Sopenharmony_ci tegra_vde_writel(vde, vde->secure_bo->dma_addr, vde->sxe, 0x7c); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci value = 0x10000005; 40662306a36Sopenharmony_ci value |= ctx->pic_width_in_mbs << 11; 40762306a36Sopenharmony_ci value |= ctx->pic_height_in_mbs << 3; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci tegra_vde_writel(vde, value, vde->mbe, 0x80); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci value = 0x26800000; 41262306a36Sopenharmony_ci value |= ctx->level_idc << 4; 41362306a36Sopenharmony_ci value |= !ctx->baseline_profile << 1; 41462306a36Sopenharmony_ci value |= !!ctx->direct_8x8_inference_flag; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci tegra_vde_writel(vde, value, vde->mbe, 0x80); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci tegra_vde_writel(vde, 0xF4000001, vde->mbe, 0x80); 41962306a36Sopenharmony_ci tegra_vde_writel(vde, 0x20000000, vde->mbe, 0x80); 42062306a36Sopenharmony_ci tegra_vde_writel(vde, 0xF4000101, vde->mbe, 0x80); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci value = 0x20000000; 42362306a36Sopenharmony_ci value |= ctx->chroma_qp_index_offset << 8; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci tegra_vde_writel(vde, value, vde->mbe, 0x80); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci err = tegra_vde_setup_mbe_frame_idx(vde, 42862306a36Sopenharmony_ci ctx->dpb_frames_nb - 1, 42962306a36Sopenharmony_ci ctx->pic_order_cnt_type == 0); 43062306a36Sopenharmony_ci if (err) { 43162306a36Sopenharmony_ci dev_err(dev, "MBE frames setup failed %d\n", err); 43262306a36Sopenharmony_ci return err; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci tegra_vde_mbe_set_0xa_reg(vde, 0, 0x000009FC); 43662306a36Sopenharmony_ci tegra_vde_mbe_set_0xa_reg(vde, 2, 0x61DEAD00); 43762306a36Sopenharmony_ci tegra_vde_mbe_set_0xa_reg(vde, 4, 0x62DEAD00); 43862306a36Sopenharmony_ci tegra_vde_mbe_set_0xa_reg(vde, 6, 0x63DEAD00); 43962306a36Sopenharmony_ci tegra_vde_mbe_set_0xa_reg(vde, 8, dpb_frames[0].aux_addr); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci value = 0xFC000000; 44262306a36Sopenharmony_ci value |= !!(dpb_frames[0].flags & FLAG_B_FRAME) << 2; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (!ctx->baseline_profile) 44562306a36Sopenharmony_ci value |= !!(dpb_frames[0].flags & FLAG_REFERENCE) << 1; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci tegra_vde_writel(vde, value, vde->mbe, 0x80); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci err = tegra_vde_wait_mbe(vde); 45062306a36Sopenharmony_ci if (err) { 45162306a36Sopenharmony_ci dev_err(dev, "MBE programming failed %d\n", err); 45262306a36Sopenharmony_ci return err; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci return 0; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic void tegra_vde_decode_frame(struct tegra_vde *vde, 45962306a36Sopenharmony_ci unsigned int macroblocks_nb) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci reinit_completion(&vde->decode_completion); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci tegra_vde_writel(vde, 0x00000001, vde->bsev, 0x8C); 46462306a36Sopenharmony_ci tegra_vde_writel(vde, 0x20000000 | (macroblocks_nb - 1), 46562306a36Sopenharmony_ci vde->sxe, 0x00); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic int tegra_vde_validate_h264_ctx(struct device *dev, 46962306a36Sopenharmony_ci struct tegra_vde_h264_decoder_ctx *ctx) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci if (ctx->dpb_frames_nb == 0 || ctx->dpb_frames_nb > 17) { 47262306a36Sopenharmony_ci dev_err(dev, "Bad DPB size %u\n", ctx->dpb_frames_nb); 47362306a36Sopenharmony_ci return -EINVAL; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (ctx->level_idc > 15) { 47762306a36Sopenharmony_ci dev_err(dev, "Bad level value %u\n", ctx->level_idc); 47862306a36Sopenharmony_ci return -EINVAL; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (ctx->pic_init_qp > 52) { 48262306a36Sopenharmony_ci dev_err(dev, "Bad pic_init_qp value %u\n", ctx->pic_init_qp); 48362306a36Sopenharmony_ci return -EINVAL; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (ctx->log2_max_pic_order_cnt_lsb > 16) { 48762306a36Sopenharmony_ci dev_err(dev, "Bad log2_max_pic_order_cnt_lsb value %u\n", 48862306a36Sopenharmony_ci ctx->log2_max_pic_order_cnt_lsb); 48962306a36Sopenharmony_ci return -EINVAL; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (ctx->log2_max_frame_num > 16) { 49362306a36Sopenharmony_ci dev_err(dev, "Bad log2_max_frame_num value %u\n", 49462306a36Sopenharmony_ci ctx->log2_max_frame_num); 49562306a36Sopenharmony_ci return -EINVAL; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (ctx->chroma_qp_index_offset > 31) { 49962306a36Sopenharmony_ci dev_err(dev, "Bad chroma_qp_index_offset value %u\n", 50062306a36Sopenharmony_ci ctx->chroma_qp_index_offset); 50162306a36Sopenharmony_ci return -EINVAL; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (ctx->pic_order_cnt_type > 2) { 50562306a36Sopenharmony_ci dev_err(dev, "Bad pic_order_cnt_type value %u\n", 50662306a36Sopenharmony_ci ctx->pic_order_cnt_type); 50762306a36Sopenharmony_ci return -EINVAL; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (ctx->num_ref_idx_l0_active_minus1 > 15) { 51162306a36Sopenharmony_ci dev_err(dev, "Bad num_ref_idx_l0_active_minus1 value %u\n", 51262306a36Sopenharmony_ci ctx->num_ref_idx_l0_active_minus1); 51362306a36Sopenharmony_ci return -EINVAL; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (ctx->num_ref_idx_l1_active_minus1 > 15) { 51762306a36Sopenharmony_ci dev_err(dev, "Bad num_ref_idx_l1_active_minus1 value %u\n", 51862306a36Sopenharmony_ci ctx->num_ref_idx_l1_active_minus1); 51962306a36Sopenharmony_ci return -EINVAL; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (!ctx->pic_width_in_mbs || ctx->pic_width_in_mbs > 127) { 52362306a36Sopenharmony_ci dev_err(dev, "Bad pic_width_in_mbs value %u\n", 52462306a36Sopenharmony_ci ctx->pic_width_in_mbs); 52562306a36Sopenharmony_ci return -EINVAL; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (!ctx->pic_height_in_mbs || ctx->pic_height_in_mbs > 127) { 52962306a36Sopenharmony_ci dev_err(dev, "Bad pic_height_in_mbs value %u\n", 53062306a36Sopenharmony_ci ctx->pic_height_in_mbs); 53162306a36Sopenharmony_ci return -EINVAL; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci return 0; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic int tegra_vde_decode_begin(struct tegra_vde *vde, 53862306a36Sopenharmony_ci struct tegra_vde_h264_decoder_ctx *ctx, 53962306a36Sopenharmony_ci struct tegra_video_frame *dpb_frames, 54062306a36Sopenharmony_ci dma_addr_t bitstream_data_addr, 54162306a36Sopenharmony_ci size_t bitstream_data_size) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct device *dev = vde->dev; 54462306a36Sopenharmony_ci unsigned int macroblocks_nb; 54562306a36Sopenharmony_ci int err; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci err = mutex_lock_interruptible(&vde->lock); 54862306a36Sopenharmony_ci if (err) 54962306a36Sopenharmony_ci return err; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci err = pm_runtime_resume_and_get(dev); 55262306a36Sopenharmony_ci if (err < 0) 55362306a36Sopenharmony_ci goto unlock; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* 55662306a36Sopenharmony_ci * We rely on the VDE registers reset value, otherwise VDE 55762306a36Sopenharmony_ci * causes bus lockup. 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_ci err = reset_control_assert(vde->rst_mc); 56062306a36Sopenharmony_ci if (err) { 56162306a36Sopenharmony_ci dev_err(dev, "DEC start: Failed to assert MC reset: %d\n", 56262306a36Sopenharmony_ci err); 56362306a36Sopenharmony_ci goto put_runtime_pm; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci err = reset_control_reset(vde->rst); 56762306a36Sopenharmony_ci if (err) { 56862306a36Sopenharmony_ci dev_err(dev, "DEC start: Failed to reset HW: %d\n", err); 56962306a36Sopenharmony_ci goto put_runtime_pm; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci err = reset_control_deassert(vde->rst_mc); 57362306a36Sopenharmony_ci if (err) { 57462306a36Sopenharmony_ci dev_err(dev, "DEC start: Failed to deassert MC reset: %d\n", 57562306a36Sopenharmony_ci err); 57662306a36Sopenharmony_ci goto put_runtime_pm; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci macroblocks_nb = ctx->pic_width_in_mbs * ctx->pic_height_in_mbs; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci err = tegra_vde_setup_hw_context(vde, ctx, dpb_frames, 58262306a36Sopenharmony_ci bitstream_data_addr, 58362306a36Sopenharmony_ci bitstream_data_size, 58462306a36Sopenharmony_ci macroblocks_nb); 58562306a36Sopenharmony_ci if (err) 58662306a36Sopenharmony_ci goto put_runtime_pm; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci tegra_vde_decode_frame(vde, macroblocks_nb); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return 0; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ciput_runtime_pm: 59362306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev); 59462306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ciunlock: 59762306a36Sopenharmony_ci mutex_unlock(&vde->lock); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci return err; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic void tegra_vde_decode_abort(struct tegra_vde *vde) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct device *dev = vde->dev; 60562306a36Sopenharmony_ci int err; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* 60862306a36Sopenharmony_ci * At first reset memory client to avoid resetting VDE HW in the 60962306a36Sopenharmony_ci * middle of DMA which could result into memory corruption or hang 61062306a36Sopenharmony_ci * the whole system. 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_ci err = reset_control_assert(vde->rst_mc); 61362306a36Sopenharmony_ci if (err) 61462306a36Sopenharmony_ci dev_err(dev, "DEC end: Failed to assert MC reset: %d\n", err); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci err = reset_control_assert(vde->rst); 61762306a36Sopenharmony_ci if (err) 61862306a36Sopenharmony_ci dev_err(dev, "DEC end: Failed to assert HW reset: %d\n", err); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev); 62162306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci mutex_unlock(&vde->lock); 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic int tegra_vde_decode_end(struct tegra_vde *vde) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci unsigned int read_bytes, macroblocks_nb; 62962306a36Sopenharmony_ci struct device *dev = vde->dev; 63062306a36Sopenharmony_ci dma_addr_t bsev_ptr; 63162306a36Sopenharmony_ci long timeout; 63262306a36Sopenharmony_ci int ret; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci timeout = wait_for_completion_interruptible_timeout( 63562306a36Sopenharmony_ci &vde->decode_completion, msecs_to_jiffies(1000)); 63662306a36Sopenharmony_ci if (timeout == 0) { 63762306a36Sopenharmony_ci bsev_ptr = tegra_vde_readl(vde, vde->bsev, 0x10); 63862306a36Sopenharmony_ci macroblocks_nb = tegra_vde_readl(vde, vde->sxe, 0xC8) & 0x1FFF; 63962306a36Sopenharmony_ci read_bytes = bsev_ptr ? bsev_ptr - vde->bitstream_data_addr : 0; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci dev_err(dev, "Decoding failed: read 0x%X bytes, %u macroblocks parsed\n", 64262306a36Sopenharmony_ci read_bytes, macroblocks_nb); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci ret = -EIO; 64562306a36Sopenharmony_ci } else if (timeout < 0) { 64662306a36Sopenharmony_ci ret = timeout; 64762306a36Sopenharmony_ci } else { 64862306a36Sopenharmony_ci ret = 0; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci tegra_vde_decode_abort(vde); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return ret; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic struct vb2_buffer *get_ref_buf(struct tegra_ctx *ctx, 65762306a36Sopenharmony_ci struct vb2_v4l2_buffer *dst, 65862306a36Sopenharmony_ci unsigned int dpb_idx) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci const struct v4l2_h264_dpb_entry *dpb = ctx->h264.decode_params->dpb; 66162306a36Sopenharmony_ci struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; 66262306a36Sopenharmony_ci struct vb2_buffer *vb = NULL; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) 66562306a36Sopenharmony_ci vb = vb2_find_buffer(cap_q, dpb[dpb_idx].reference_ts); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* 66862306a36Sopenharmony_ci * If a DPB entry is unused or invalid, address of current destination 66962306a36Sopenharmony_ci * buffer is returned. 67062306a36Sopenharmony_ci */ 67162306a36Sopenharmony_ci if (!vb) 67262306a36Sopenharmony_ci return &dst->vb2_buf; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci return vb; 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic int tegra_vde_validate_vb_size(struct tegra_ctx *ctx, 67862306a36Sopenharmony_ci struct vb2_buffer *vb, 67962306a36Sopenharmony_ci unsigned int plane_id, 68062306a36Sopenharmony_ci size_t min_size) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci u64 offset = vb->planes[plane_id].data_offset; 68362306a36Sopenharmony_ci struct device *dev = ctx->vde->dev; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (offset + min_size > vb2_plane_size(vb, plane_id)) { 68662306a36Sopenharmony_ci dev_err(dev, "Too small plane[%u] size %lu @0x%llX, should be at least %zu\n", 68762306a36Sopenharmony_ci plane_id, vb2_plane_size(vb, plane_id), offset, min_size); 68862306a36Sopenharmony_ci return -EINVAL; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return 0; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int tegra_vde_h264_setup_frame(struct tegra_ctx *ctx, 69562306a36Sopenharmony_ci struct tegra_vde_h264_decoder_ctx *h264, 69662306a36Sopenharmony_ci struct v4l2_h264_reflist_builder *b, 69762306a36Sopenharmony_ci struct vb2_buffer *vb, 69862306a36Sopenharmony_ci unsigned int ref_id, 69962306a36Sopenharmony_ci unsigned int id) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pixfmt = &ctx->decoded_fmt.fmt.pix_mp; 70262306a36Sopenharmony_ci struct tegra_m2m_buffer *tb = vb_to_tegra_buf(vb); 70362306a36Sopenharmony_ci struct tegra_ctx_h264 *h = &ctx->h264; 70462306a36Sopenharmony_ci struct tegra_vde *vde = ctx->vde; 70562306a36Sopenharmony_ci struct device *dev = vde->dev; 70662306a36Sopenharmony_ci unsigned int cstride, lstride; 70762306a36Sopenharmony_ci unsigned int flags = 0; 70862306a36Sopenharmony_ci size_t lsize, csize; 70962306a36Sopenharmony_ci int err, frame_num; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci lsize = h264->pic_width_in_mbs * 16 * h264->pic_height_in_mbs * 16; 71262306a36Sopenharmony_ci csize = h264->pic_width_in_mbs * 8 * h264->pic_height_in_mbs * 8; 71362306a36Sopenharmony_ci lstride = pixfmt->plane_fmt[0].bytesperline; 71462306a36Sopenharmony_ci cstride = pixfmt->plane_fmt[1].bytesperline; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci err = tegra_vde_validate_vb_size(ctx, vb, 0, lsize); 71762306a36Sopenharmony_ci if (err) 71862306a36Sopenharmony_ci return err; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci err = tegra_vde_validate_vb_size(ctx, vb, 1, csize); 72162306a36Sopenharmony_ci if (err) 72262306a36Sopenharmony_ci return err; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci err = tegra_vde_validate_vb_size(ctx, vb, 2, csize); 72562306a36Sopenharmony_ci if (err) 72662306a36Sopenharmony_ci return err; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (!tb->aux || tb->aux->size < csize) { 72962306a36Sopenharmony_ci dev_err(dev, "Too small aux size %zd, should be at least %zu\n", 73062306a36Sopenharmony_ci tb->aux ? tb->aux->size : -1, csize); 73162306a36Sopenharmony_ci return -EINVAL; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (id == 0) { 73562306a36Sopenharmony_ci frame_num = h->decode_params->frame_num; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (h->decode_params->nal_ref_idc) 73862306a36Sopenharmony_ci flags |= FLAG_REFERENCE; 73962306a36Sopenharmony_ci } else { 74062306a36Sopenharmony_ci frame_num = b->refs[ref_id].frame_num; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (tb->b_frame) 74462306a36Sopenharmony_ci flags |= FLAG_B_FRAME; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci vde->frames[id].flags = flags; 74762306a36Sopenharmony_ci vde->frames[id].y_addr = tb->dma_addr[0]; 74862306a36Sopenharmony_ci vde->frames[id].cb_addr = tb->dma_addr[1]; 74962306a36Sopenharmony_ci vde->frames[id].cr_addr = tb->dma_addr[2]; 75062306a36Sopenharmony_ci vde->frames[id].aux_addr = tb->aux->dma_addr; 75162306a36Sopenharmony_ci vde->frames[id].frame_num = frame_num & 0x7fffff; 75262306a36Sopenharmony_ci vde->frames[id].luma_atoms_pitch = lstride / VDE_ATOM; 75362306a36Sopenharmony_ci vde->frames[id].chroma_atoms_pitch = cstride / VDE_ATOM; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci return 0; 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_cistatic int tegra_vde_h264_setup_frames(struct tegra_ctx *ctx, 75962306a36Sopenharmony_ci struct tegra_vde_h264_decoder_ctx *h264) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 76262306a36Sopenharmony_ci struct vb2_v4l2_buffer *dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 76362306a36Sopenharmony_ci const struct v4l2_h264_dpb_entry *dpb = ctx->h264.decode_params->dpb; 76462306a36Sopenharmony_ci struct tegra_m2m_buffer *tb = vb_to_tegra_buf(&dst->vb2_buf); 76562306a36Sopenharmony_ci struct tegra_ctx_h264 *h = &ctx->h264; 76662306a36Sopenharmony_ci struct v4l2_h264_reflist_builder b; 76762306a36Sopenharmony_ci struct v4l2_h264_reference *dpb_id; 76862306a36Sopenharmony_ci struct h264_reflists reflists; 76962306a36Sopenharmony_ci struct vb2_buffer *ref; 77062306a36Sopenharmony_ci unsigned int i; 77162306a36Sopenharmony_ci int err; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci /* 77462306a36Sopenharmony_ci * Tegra hardware requires information about frame's type, assuming 77562306a36Sopenharmony_ci * that frame consists of the same type slices. Userspace must tag 77662306a36Sopenharmony_ci * frame's type appropriately. 77762306a36Sopenharmony_ci * 77862306a36Sopenharmony_ci * Decoding of a non-uniform frames isn't supported by hardware and 77962306a36Sopenharmony_ci * require software preprocessing that we don't implement. Decoding 78062306a36Sopenharmony_ci * is expected to fail in this case. Such video streams are rare in 78162306a36Sopenharmony_ci * practice, so not a big deal. 78262306a36Sopenharmony_ci * 78362306a36Sopenharmony_ci * If userspace doesn't tell us frame's type, then we will try decode 78462306a36Sopenharmony_ci * as-is. 78562306a36Sopenharmony_ci */ 78662306a36Sopenharmony_ci v4l2_m2m_buf_copy_metadata(src, dst, true); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (h->decode_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BFRAME) 78962306a36Sopenharmony_ci tb->b_frame = true; 79062306a36Sopenharmony_ci else 79162306a36Sopenharmony_ci tb->b_frame = false; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci err = tegra_vde_h264_setup_frame(ctx, h264, NULL, &dst->vb2_buf, 0, 79462306a36Sopenharmony_ci h264->dpb_frames_nb++); 79562306a36Sopenharmony_ci if (err) 79662306a36Sopenharmony_ci return err; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (!(h->decode_params->flags & (V4L2_H264_DECODE_PARAM_FLAG_PFRAME | 79962306a36Sopenharmony_ci V4L2_H264_DECODE_PARAM_FLAG_BFRAME))) 80062306a36Sopenharmony_ci return 0; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci v4l2_h264_init_reflist_builder(&b, h->decode_params, h->sps, dpb); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci if (h->decode_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BFRAME) { 80562306a36Sopenharmony_ci v4l2_h264_build_b_ref_lists(&b, reflists.b0, reflists.b1); 80662306a36Sopenharmony_ci dpb_id = reflists.b0; 80762306a36Sopenharmony_ci } else { 80862306a36Sopenharmony_ci v4l2_h264_build_p_ref_list(&b, reflists.p); 80962306a36Sopenharmony_ci dpb_id = reflists.p; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci for (i = 0; i < b.num_valid; i++) { 81362306a36Sopenharmony_ci int dpb_idx = dpb_id[i].index; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci ref = get_ref_buf(ctx, dst, dpb_idx); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci err = tegra_vde_h264_setup_frame(ctx, h264, &b, ref, dpb_idx, 81862306a36Sopenharmony_ci h264->dpb_frames_nb++); 81962306a36Sopenharmony_ci if (err) 82062306a36Sopenharmony_ci return err; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci if (b.refs[dpb_idx].top_field_order_cnt < b.cur_pic_order_count) 82362306a36Sopenharmony_ci h264->dpb_ref_frames_with_earlier_poc_nb++; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci return 0; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic unsigned int to_tegra_vde_h264_level_idc(unsigned int level_idc) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci switch (level_idc) { 83262306a36Sopenharmony_ci case 11: 83362306a36Sopenharmony_ci return 2; 83462306a36Sopenharmony_ci case 12: 83562306a36Sopenharmony_ci return 3; 83662306a36Sopenharmony_ci case 13: 83762306a36Sopenharmony_ci return 4; 83862306a36Sopenharmony_ci case 20: 83962306a36Sopenharmony_ci return 5; 84062306a36Sopenharmony_ci case 21: 84162306a36Sopenharmony_ci return 6; 84262306a36Sopenharmony_ci case 22: 84362306a36Sopenharmony_ci return 7; 84462306a36Sopenharmony_ci case 30: 84562306a36Sopenharmony_ci return 8; 84662306a36Sopenharmony_ci case 31: 84762306a36Sopenharmony_ci return 9; 84862306a36Sopenharmony_ci case 32: 84962306a36Sopenharmony_ci return 10; 85062306a36Sopenharmony_ci case 40: 85162306a36Sopenharmony_ci return 11; 85262306a36Sopenharmony_ci case 41: 85362306a36Sopenharmony_ci return 12; 85462306a36Sopenharmony_ci case 42: 85562306a36Sopenharmony_ci return 13; 85662306a36Sopenharmony_ci case 50: 85762306a36Sopenharmony_ci return 14; 85862306a36Sopenharmony_ci default: 85962306a36Sopenharmony_ci break; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return 15; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic int tegra_vde_h264_setup_context(struct tegra_ctx *ctx, 86662306a36Sopenharmony_ci struct tegra_vde_h264_decoder_ctx *h264) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci struct tegra_ctx_h264 *h = &ctx->h264; 86962306a36Sopenharmony_ci struct tegra_vde *vde = ctx->vde; 87062306a36Sopenharmony_ci struct device *dev = vde->dev; 87162306a36Sopenharmony_ci int err; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci memset(h264, 0, sizeof(*h264)); 87462306a36Sopenharmony_ci memset(vde->frames, 0, sizeof(vde->frames)); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci tegra_vde_prepare_control_data(ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); 87762306a36Sopenharmony_ci tegra_vde_prepare_control_data(ctx, V4L2_CID_STATELESS_H264_SPS); 87862306a36Sopenharmony_ci tegra_vde_prepare_control_data(ctx, V4L2_CID_STATELESS_H264_PPS); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci /* CABAC unsupported by hardware, requires software preprocessing */ 88162306a36Sopenharmony_ci if (h->pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) 88262306a36Sopenharmony_ci return -EOPNOTSUPP; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (h->decode_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) 88562306a36Sopenharmony_ci return -EOPNOTSUPP; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci if (h->sps->profile_idc == 66) 88862306a36Sopenharmony_ci h264->baseline_profile = 1; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (h->sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) 89162306a36Sopenharmony_ci h264->direct_8x8_inference_flag = 1; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (h->pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) 89462306a36Sopenharmony_ci h264->constrained_intra_pred_flag = 1; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci if (h->pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) 89762306a36Sopenharmony_ci h264->deblocking_filter_control_present_flag = 1; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci if (h->pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT) 90062306a36Sopenharmony_ci h264->pic_order_present_flag = 1; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci h264->level_idc = to_tegra_vde_h264_level_idc(h->sps->level_idc); 90362306a36Sopenharmony_ci h264->log2_max_pic_order_cnt_lsb = h->sps->log2_max_pic_order_cnt_lsb_minus4 + 4; 90462306a36Sopenharmony_ci h264->log2_max_frame_num = h->sps->log2_max_frame_num_minus4 + 4; 90562306a36Sopenharmony_ci h264->pic_order_cnt_type = h->sps->pic_order_cnt_type; 90662306a36Sopenharmony_ci h264->pic_width_in_mbs = h->sps->pic_width_in_mbs_minus1 + 1; 90762306a36Sopenharmony_ci h264->pic_height_in_mbs = h->sps->pic_height_in_map_units_minus1 + 1; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci h264->num_ref_idx_l0_active_minus1 = h->pps->num_ref_idx_l0_default_active_minus1; 91062306a36Sopenharmony_ci h264->num_ref_idx_l1_active_minus1 = h->pps->num_ref_idx_l1_default_active_minus1; 91162306a36Sopenharmony_ci h264->chroma_qp_index_offset = h->pps->chroma_qp_index_offset & 0x1f; 91262306a36Sopenharmony_ci h264->pic_init_qp = h->pps->pic_init_qp_minus26 + 26; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci err = tegra_vde_h264_setup_frames(ctx, h264); 91562306a36Sopenharmony_ci if (err) 91662306a36Sopenharmony_ci return err; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci err = tegra_vde_validate_h264_ctx(dev, h264); 91962306a36Sopenharmony_ci if (err) 92062306a36Sopenharmony_ci return err; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci return 0; 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ciint tegra_vde_h264_decode_run(struct tegra_ctx *ctx) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 92862306a36Sopenharmony_ci struct tegra_m2m_buffer *bitstream = vb_to_tegra_buf(&src->vb2_buf); 92962306a36Sopenharmony_ci size_t bitstream_size = vb2_get_plane_payload(&src->vb2_buf, 0); 93062306a36Sopenharmony_ci struct tegra_vde_h264_decoder_ctx h264; 93162306a36Sopenharmony_ci struct tegra_vde *vde = ctx->vde; 93262306a36Sopenharmony_ci int err; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci err = tegra_vde_h264_setup_context(ctx, &h264); 93562306a36Sopenharmony_ci if (err) 93662306a36Sopenharmony_ci return err; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci err = tegra_vde_decode_begin(vde, &h264, vde->frames, 93962306a36Sopenharmony_ci bitstream->dma_addr[0], 94062306a36Sopenharmony_ci bitstream_size); 94162306a36Sopenharmony_ci if (err) 94262306a36Sopenharmony_ci return err; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci return 0; 94562306a36Sopenharmony_ci} 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ciint tegra_vde_h264_decode_wait(struct tegra_ctx *ctx) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci return tegra_vde_decode_end(ctx->vde); 95062306a36Sopenharmony_ci} 951