Files
linux/drivers/media/platform/qcom/iris/iris_vpu_buffer.c
Dikshita Agarwal 73702f45db media: iris: allocate, initialize and queue internal buffers
Implement the functions for creating, queueing, releasing and destroying
the buffers for internal usage.

Tested-by: Stefan Schmidt <stefan.schmidt@linaro.org> # x1e80100 (Dell XPS 13 9345)
Reviewed-by: Stefan Schmidt <stefan.schmidt@linaro.org>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-HDK
Signed-off-by: Dikshita Agarwal <quic_dikshita@quicinc.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
2025-02-07 11:51:42 +01:00

271 lines
8.2 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "iris_instance.h"
#include "iris_vpu_buffer.h"
static u32 size_h264d_hw_bin_buffer(u32 frame_width, u32 frame_height, u32 num_vpp_pipes)
{
u32 size_yuv, size_bin_hdr, size_bin_res;
size_yuv = ((frame_width * frame_height) <= BIN_BUFFER_THRESHOLD) ?
((BIN_BUFFER_THRESHOLD * 3) >> 1) :
((frame_width * frame_height * 3) >> 1);
size_bin_hdr = size_yuv * H264_CABAC_HDR_RATIO_HD_TOT;
size_bin_res = size_yuv * H264_CABAC_RES_RATIO_HD_TOT;
size_bin_hdr = ALIGN(size_bin_hdr / num_vpp_pipes,
DMA_ALIGNMENT) * num_vpp_pipes;
size_bin_res = ALIGN(size_bin_res / num_vpp_pipes,
DMA_ALIGNMENT) * num_vpp_pipes;
return size_bin_hdr + size_bin_res;
}
static u32 hfi_buffer_bin_h264d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes)
{
u32 n_aligned_h = ALIGN(frame_height, 16);
u32 n_aligned_w = ALIGN(frame_width, 16);
return size_h264d_hw_bin_buffer(n_aligned_w, n_aligned_h, num_vpp_pipes);
}
static u32 hfi_buffer_comv_h264d(u32 frame_width, u32 frame_height, u32 _comv_bufcount)
{
u32 frame_height_in_mbs = DIV_ROUND_UP(frame_height, 16);
u32 frame_width_in_mbs = DIV_ROUND_UP(frame_width, 16);
u32 col_zero_aligned_width = (frame_width_in_mbs << 2);
u32 col_mv_aligned_width = (frame_width_in_mbs << 7);
u32 col_zero_size, size_colloc;
col_mv_aligned_width = ALIGN(col_mv_aligned_width, 16);
col_zero_aligned_width = ALIGN(col_zero_aligned_width, 16);
col_zero_size = col_zero_aligned_width *
((frame_height_in_mbs + 1) >> 1);
col_zero_size = ALIGN(col_zero_size, 64);
col_zero_size <<= 1;
col_zero_size = ALIGN(col_zero_size, 512);
size_colloc = col_mv_aligned_width * ((frame_height_in_mbs + 1) >> 1);
size_colloc = ALIGN(size_colloc, 64);
size_colloc <<= 1;
size_colloc = ALIGN(size_colloc, 512);
size_colloc += (col_zero_size + SIZE_H264D_BUFTAB_T * 2);
return (size_colloc * (_comv_bufcount)) + 512;
}
static u32 size_h264d_bse_cmd_buf(u32 frame_height)
{
u32 height = ALIGN(frame_height, 32);
return min_t(u32, (DIV_ROUND_UP(height, 16) * 48), H264D_MAX_SLICE) *
SIZE_H264D_BSE_CMD_PER_BUF;
}
static u32 size_h264d_vpp_cmd_buf(u32 frame_height)
{
u32 size, height = ALIGN(frame_height, 32);
size = min_t(u32, (DIV_ROUND_UP(height, 16) * 48), H264D_MAX_SLICE) *
SIZE_H264D_VPP_CMD_PER_BUF;
return size > VPP_CMD_MAX_SIZE ? VPP_CMD_MAX_SIZE : size;
}
static u32 hfi_buffer_persist_h264d(void)
{
return ALIGN(SIZE_SLIST_BUF_H264 * NUM_SLIST_BUF_H264 +
H264_DISPLAY_BUF_SIZE * H264_NUM_FRM_INFO +
NUM_HW_PIC_BUF * SIZE_SEI_USERDATA,
DMA_ALIGNMENT);
}
static u32 hfi_buffer_non_comv_h264d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes)
{
u32 size_bse, size_vpp, size;
size_bse = size_h264d_bse_cmd_buf(frame_height);
size_vpp = size_h264d_vpp_cmd_buf(frame_height);
size = ALIGN(size_bse, DMA_ALIGNMENT) +
ALIGN(size_vpp, DMA_ALIGNMENT) +
ALIGN(SIZE_HW_PIC(SIZE_H264D_HW_PIC_T), DMA_ALIGNMENT);
return ALIGN(size, DMA_ALIGNMENT);
}
static u32 size_vpss_lb(u32 frame_width, u32 frame_height)
{
u32 opb_lb_wr_llb_y_buffer_size, opb_lb_wr_llb_uv_buffer_size;
u32 opb_wr_top_line_chroma_buffer_size;
u32 opb_wr_top_line_luma_buffer_size;
u32 macrotiling_size = 32;
opb_wr_top_line_luma_buffer_size =
ALIGN(frame_width, macrotiling_size) / macrotiling_size * 256;
opb_wr_top_line_luma_buffer_size =
ALIGN(opb_wr_top_line_luma_buffer_size, DMA_ALIGNMENT) +
(MAX_TILE_COLUMNS - 1) * 256;
opb_wr_top_line_luma_buffer_size =
max_t(u32, opb_wr_top_line_luma_buffer_size, (32 * ALIGN(frame_height, 8)));
opb_wr_top_line_chroma_buffer_size = opb_wr_top_line_luma_buffer_size;
opb_lb_wr_llb_uv_buffer_size =
ALIGN((ALIGN(frame_height, 8) / (4 / 2)) * 64, 32);
opb_lb_wr_llb_y_buffer_size =
ALIGN((ALIGN(frame_height, 8) / (4 / 2)) * 64, 32);
return opb_wr_top_line_luma_buffer_size +
opb_wr_top_line_chroma_buffer_size +
opb_lb_wr_llb_uv_buffer_size +
opb_lb_wr_llb_y_buffer_size;
}
static u32 hfi_buffer_line_h264d(u32 frame_width, u32 frame_height,
bool is_opb, u32 num_vpp_pipes)
{
u32 vpss_lb_size = 0;
u32 size;
size = ALIGN(size_h264d_lb_fe_top_data(frame_width), DMA_ALIGNMENT) +
ALIGN(size_h264d_lb_fe_top_ctrl(frame_width), DMA_ALIGNMENT) +
ALIGN(size_h264d_lb_fe_left_ctrl(frame_height), DMA_ALIGNMENT) * num_vpp_pipes +
ALIGN(size_h264d_lb_se_top_ctrl(frame_width), DMA_ALIGNMENT) +
ALIGN(size_h264d_lb_se_left_ctrl(frame_height), DMA_ALIGNMENT) * num_vpp_pipes +
ALIGN(size_h264d_lb_pe_top_data(frame_width), DMA_ALIGNMENT) +
ALIGN(size_h264d_lb_vsp_top(frame_width), DMA_ALIGNMENT) +
ALIGN(size_h264d_lb_recon_dma_metadata_wr(frame_height), DMA_ALIGNMENT) * 2 +
ALIGN(size_h264d_qp(frame_width, frame_height), DMA_ALIGNMENT);
size = ALIGN(size, DMA_ALIGNMENT);
if (is_opb)
vpss_lb_size = size_vpss_lb(frame_width, frame_height);
return ALIGN((size + vpss_lb_size), DMA_ALIGNMENT);
}
static u32 iris_vpu_dec_bin_size(struct iris_inst *inst)
{
u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe;
struct v4l2_format *f = inst->fmt_src;
u32 height = f->fmt.pix_mp.height;
u32 width = f->fmt.pix_mp.width;
return hfi_buffer_bin_h264d(width, height, num_vpp_pipes);
}
static u32 iris_vpu_dec_comv_size(struct iris_inst *inst)
{
u32 num_comv = VIDEO_MAX_FRAME;
struct v4l2_format *f = inst->fmt_src;
u32 height = f->fmt.pix_mp.height;
u32 width = f->fmt.pix_mp.width;
return hfi_buffer_comv_h264d(width, height, num_comv);
}
static u32 iris_vpu_dec_persist_size(struct iris_inst *inst)
{
return hfi_buffer_persist_h264d();
}
static u32 iris_vpu_dec_dpb_size(struct iris_inst *inst)
{
if (iris_split_mode_enabled(inst))
return iris_get_buffer_size(inst, BUF_DPB);
else
return 0;
}
static u32 iris_vpu_dec_non_comv_size(struct iris_inst *inst)
{
u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe;
struct v4l2_format *f = inst->fmt_src;
u32 height = f->fmt.pix_mp.height;
u32 width = f->fmt.pix_mp.width;
return hfi_buffer_non_comv_h264d(width, height, num_vpp_pipes);
}
static u32 iris_vpu_dec_line_size(struct iris_inst *inst)
{
u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe;
struct v4l2_format *f = inst->fmt_src;
u32 height = f->fmt.pix_mp.height;
u32 width = f->fmt.pix_mp.width;
bool is_opb = false;
if (iris_split_mode_enabled(inst))
is_opb = true;
return hfi_buffer_line_h264d(width, height, is_opb, num_vpp_pipes);
}
static u32 iris_vpu_dec_scratch1_size(struct iris_inst *inst)
{
return iris_vpu_dec_comv_size(inst) +
iris_vpu_dec_non_comv_size(inst) +
iris_vpu_dec_line_size(inst);
}
struct iris_vpu_buf_type_handle {
enum iris_buffer_type type;
u32 (*handle)(struct iris_inst *inst);
};
int iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type)
{
const struct iris_vpu_buf_type_handle *buf_type_handle_arr;
u32 size = 0, buf_type_handle_size, i;
static const struct iris_vpu_buf_type_handle dec_internal_buf_type_handle[] = {
{BUF_BIN, iris_vpu_dec_bin_size },
{BUF_COMV, iris_vpu_dec_comv_size },
{BUF_NON_COMV, iris_vpu_dec_non_comv_size },
{BUF_LINE, iris_vpu_dec_line_size },
{BUF_PERSIST, iris_vpu_dec_persist_size },
{BUF_DPB, iris_vpu_dec_dpb_size },
{BUF_SCRATCH_1, iris_vpu_dec_scratch1_size },
};
buf_type_handle_size = ARRAY_SIZE(dec_internal_buf_type_handle);
buf_type_handle_arr = dec_internal_buf_type_handle;
for (i = 0; i < buf_type_handle_size; i++) {
if (buf_type_handle_arr[i].type == buffer_type) {
size = buf_type_handle_arr[i].handle(inst);
break;
}
}
return size;
}
static inline int iris_vpu_dpb_count(struct iris_inst *inst)
{
if (iris_split_mode_enabled(inst)) {
return inst->fw_min_count ?
inst->fw_min_count : inst->buffers[BUF_OUTPUT].min_count;
}
return 0;
}
int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type)
{
switch (buffer_type) {
case BUF_INPUT:
return MIN_BUFFERS;
case BUF_OUTPUT:
return inst->fw_min_count;
case BUF_BIN:
case BUF_COMV:
case BUF_NON_COMV:
case BUF_LINE:
case BUF_PERSIST:
case BUF_SCRATCH_1:
return 1; /* internal buffer count needed by firmware is 1 */
case BUF_DPB:
return iris_vpu_dpb_count(inst);
default:
return 0;
}
}