288 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Hantro VPU HEVC codec driver4 *5 * Copyright (C) 2020 Safran Passenger Innovations LLC6 */7 8#include <linux/types.h>9#include <media/v4l2-mem2mem.h>10 11#include "hantro.h"12#include "hantro_hw.h"13 14#define VERT_FILTER_RAM_SIZE 8 /* bytes per pixel row */15/*16 * BSD control data of current picture at tile border17 * 128 bits per 4x4 tile = 128/(8*4) bytes per row18 */19#define BSD_CTRL_RAM_SIZE 4 /* bytes per pixel row */20/* tile border coefficients of filter */21#define VERT_SAO_RAM_SIZE 48 /* bytes per pixel */22 23#define SCALING_LIST_SIZE (16 * 64)24 25#define MAX_TILE_COLS 2026#define MAX_TILE_ROWS 2227 28static bool hevc_use_compression = IS_ENABLED(CONFIG_VIDEO_HANTRO_HEVC_RFC);29module_param_named(hevc_use_compression, hevc_use_compression, bool, 0644);30MODULE_PARM_DESC(hevc_use_compression,31 "Use reference frame compression for HEVC");32 33void hantro_hevc_ref_init(struct hantro_ctx *ctx)34{35 struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;36 37 hevc_dec->ref_bufs_used = 0;38}39 40dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx,41 s32 poc)42{43 struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;44 int i;45 46 /* Find the reference buffer in already known ones */47 for (i = 0; i < NUM_REF_PICTURES; i++) {48 if (hevc_dec->ref_bufs_poc[i] == poc) {49 hevc_dec->ref_bufs_used |= 1 << i;50 return hevc_dec->ref_bufs[i].dma;51 }52 }53 54 return 0;55}56 57int hantro_hevc_add_ref_buf(struct hantro_ctx *ctx, int poc, dma_addr_t addr)58{59 struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;60 int i;61 62 /* Add a new reference buffer */63 for (i = 0; i < NUM_REF_PICTURES; i++) {64 if (!(hevc_dec->ref_bufs_used & 1 << i)) {65 hevc_dec->ref_bufs_used |= 1 << i;66 hevc_dec->ref_bufs_poc[i] = poc;67 hevc_dec->ref_bufs[i].dma = addr;68 return 0;69 }70 }71 72 return -EINVAL;73}74 75static int tile_buffer_reallocate(struct hantro_ctx *ctx)76{77 struct hantro_dev *vpu = ctx->dev;78 struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;79 const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;80 const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps;81 const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;82 unsigned int num_tile_cols = pps->num_tile_columns_minus1 + 1;83 unsigned int height64 = (sps->pic_height_in_luma_samples + 63) & ~63;84 unsigned int size;85 86 if (num_tile_cols <= 1 ||87 num_tile_cols <= hevc_dec->num_tile_cols_allocated)88 return 0;89 90 /* Need to reallocate due to tiles passed via PPS */91 if (hevc_dec->tile_filter.cpu) {92 dma_free_coherent(vpu->dev, hevc_dec->tile_filter.size,93 hevc_dec->tile_filter.cpu,94 hevc_dec->tile_filter.dma);95 hevc_dec->tile_filter.cpu = NULL;96 }97 98 if (hevc_dec->tile_sao.cpu) {99 dma_free_coherent(vpu->dev, hevc_dec->tile_sao.size,100 hevc_dec->tile_sao.cpu,101 hevc_dec->tile_sao.dma);102 hevc_dec->tile_sao.cpu = NULL;103 }104 105 if (hevc_dec->tile_bsd.cpu) {106 dma_free_coherent(vpu->dev, hevc_dec->tile_bsd.size,107 hevc_dec->tile_bsd.cpu,108 hevc_dec->tile_bsd.dma);109 hevc_dec->tile_bsd.cpu = NULL;110 }111 112 size = (VERT_FILTER_RAM_SIZE * height64 * (num_tile_cols - 1) * ctx->bit_depth) / 8;113 hevc_dec->tile_filter.cpu = dma_alloc_coherent(vpu->dev, size,114 &hevc_dec->tile_filter.dma,115 GFP_KERNEL);116 if (!hevc_dec->tile_filter.cpu)117 return -ENOMEM;118 hevc_dec->tile_filter.size = size;119 120 size = (VERT_SAO_RAM_SIZE * height64 * (num_tile_cols - 1) * ctx->bit_depth) / 8;121 hevc_dec->tile_sao.cpu = dma_alloc_coherent(vpu->dev, size,122 &hevc_dec->tile_sao.dma,123 GFP_KERNEL);124 if (!hevc_dec->tile_sao.cpu)125 goto err_free_tile_buffers;126 hevc_dec->tile_sao.size = size;127 128 size = BSD_CTRL_RAM_SIZE * height64 * (num_tile_cols - 1);129 hevc_dec->tile_bsd.cpu = dma_alloc_coherent(vpu->dev, size,130 &hevc_dec->tile_bsd.dma,131 GFP_KERNEL);132 if (!hevc_dec->tile_bsd.cpu)133 goto err_free_sao_buffers;134 hevc_dec->tile_bsd.size = size;135 136 hevc_dec->num_tile_cols_allocated = num_tile_cols;137 138 return 0;139 140err_free_sao_buffers:141 if (hevc_dec->tile_sao.cpu)142 dma_free_coherent(vpu->dev, hevc_dec->tile_sao.size,143 hevc_dec->tile_sao.cpu,144 hevc_dec->tile_sao.dma);145 hevc_dec->tile_sao.cpu = NULL;146 147err_free_tile_buffers:148 if (hevc_dec->tile_filter.cpu)149 dma_free_coherent(vpu->dev, hevc_dec->tile_filter.size,150 hevc_dec->tile_filter.cpu,151 hevc_dec->tile_filter.dma);152 hevc_dec->tile_filter.cpu = NULL;153 154 return -ENOMEM;155}156 157static int hantro_hevc_validate_sps(struct hantro_ctx *ctx, const struct v4l2_ctrl_hevc_sps *sps)158{159 /*160 * for tile pixel format check if the width and height match161 * hardware constraints162 */163 if (ctx->vpu_dst_fmt->fourcc == V4L2_PIX_FMT_NV12_4L4) {164 if (ctx->dst_fmt.width !=165 ALIGN(sps->pic_width_in_luma_samples, ctx->vpu_dst_fmt->frmsize.step_width))166 return -EINVAL;167 168 if (ctx->dst_fmt.height !=169 ALIGN(sps->pic_height_in_luma_samples, ctx->vpu_dst_fmt->frmsize.step_height))170 return -EINVAL;171 }172 173 return 0;174}175 176int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx)177{178 struct hantro_hevc_dec_hw_ctx *hevc_ctx = &ctx->hevc_dec;179 struct hantro_hevc_dec_ctrls *ctrls = &hevc_ctx->ctrls;180 int ret;181 182 hantro_start_prepare_run(ctx);183 184 ctrls->decode_params =185 hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);186 if (WARN_ON(!ctrls->decode_params))187 return -EINVAL;188 189 ctrls->scaling =190 hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);191 if (WARN_ON(!ctrls->scaling))192 return -EINVAL;193 194 ctrls->sps =195 hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_SPS);196 if (WARN_ON(!ctrls->sps))197 return -EINVAL;198 199 ret = hantro_hevc_validate_sps(ctx, ctrls->sps);200 if (ret)201 return ret;202 203 ctrls->pps =204 hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_PPS);205 if (WARN_ON(!ctrls->pps))206 return -EINVAL;207 208 ret = tile_buffer_reallocate(ctx);209 if (ret)210 return ret;211 212 return 0;213}214 215void hantro_hevc_dec_exit(struct hantro_ctx *ctx)216{217 struct hantro_dev *vpu = ctx->dev;218 struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;219 220 if (hevc_dec->tile_sizes.cpu)221 dma_free_coherent(vpu->dev, hevc_dec->tile_sizes.size,222 hevc_dec->tile_sizes.cpu,223 hevc_dec->tile_sizes.dma);224 hevc_dec->tile_sizes.cpu = NULL;225 226 if (hevc_dec->scaling_lists.cpu)227 dma_free_coherent(vpu->dev, hevc_dec->scaling_lists.size,228 hevc_dec->scaling_lists.cpu,229 hevc_dec->scaling_lists.dma);230 hevc_dec->scaling_lists.cpu = NULL;231 232 if (hevc_dec->tile_filter.cpu)233 dma_free_coherent(vpu->dev, hevc_dec->tile_filter.size,234 hevc_dec->tile_filter.cpu,235 hevc_dec->tile_filter.dma);236 hevc_dec->tile_filter.cpu = NULL;237 238 if (hevc_dec->tile_sao.cpu)239 dma_free_coherent(vpu->dev, hevc_dec->tile_sao.size,240 hevc_dec->tile_sao.cpu,241 hevc_dec->tile_sao.dma);242 hevc_dec->tile_sao.cpu = NULL;243 244 if (hevc_dec->tile_bsd.cpu)245 dma_free_coherent(vpu->dev, hevc_dec->tile_bsd.size,246 hevc_dec->tile_bsd.cpu,247 hevc_dec->tile_bsd.dma);248 hevc_dec->tile_bsd.cpu = NULL;249}250 251int hantro_hevc_dec_init(struct hantro_ctx *ctx)252{253 struct hantro_dev *vpu = ctx->dev;254 struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;255 unsigned int size;256 257 memset(hevc_dec, 0, sizeof(*hevc_dec));258 259 /*260 * Maximum number of tiles times width and height (2 bytes each),261 * rounding up to next 16 bytes boundary + one extra 16 byte262 * chunk (HW guys wanted to have this).263 */264 size = round_up(MAX_TILE_COLS * MAX_TILE_ROWS * 4 * sizeof(u16) + 16, 16);265 hevc_dec->tile_sizes.cpu = dma_alloc_coherent(vpu->dev, size,266 &hevc_dec->tile_sizes.dma,267 GFP_KERNEL);268 if (!hevc_dec->tile_sizes.cpu)269 return -ENOMEM;270 271 hevc_dec->tile_sizes.size = size;272 273 hevc_dec->scaling_lists.cpu = dma_alloc_coherent(vpu->dev, SCALING_LIST_SIZE,274 &hevc_dec->scaling_lists.dma,275 GFP_KERNEL);276 if (!hevc_dec->scaling_lists.cpu)277 return -ENOMEM;278 279 hevc_dec->scaling_lists.size = SCALING_LIST_SIZE;280 281 hantro_hevc_ref_init(ctx);282 283 hevc_dec->use_compression =284 hevc_use_compression & hantro_needs_postproc(ctx, ctx->vpu_dst_fmt);285 286 return 0;287}288