drm/tests: hdmi: Fix memory leaks in drm_display_mode_from_cea_vic()
[drm/drm-misc.git] / drivers / media / platform / verisilicon / hantro_hevc.c
blob83cd12b0ddd6554ac4deb61111e9a5b771760d1c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Hantro VPU HEVC codec driver
5 * Copyright (C) 2020 Safran Passenger Innovations LLC
6 */
8 #include <linux/types.h>
9 #include <media/v4l2-mem2mem.h>
11 #include "hantro.h"
12 #include "hantro_hw.h"
14 #define VERT_FILTER_RAM_SIZE 8 /* bytes per pixel row */
16 * BSD control data of current picture at tile border
17 * 128 bits per 4x4 tile = 128/(8*4) bytes per row
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 */
23 #define SCALING_LIST_SIZE (16 * 64)
25 #define MAX_TILE_COLS 20
26 #define MAX_TILE_ROWS 22
28 static bool hevc_use_compression = IS_ENABLED(CONFIG_VIDEO_HANTRO_HEVC_RFC);
29 module_param_named(hevc_use_compression, hevc_use_compression, bool, 0644);
30 MODULE_PARM_DESC(hevc_use_compression,
31 "Use reference frame compression for HEVC");
33 void hantro_hevc_ref_init(struct hantro_ctx *ctx)
35 struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
37 hevc_dec->ref_bufs_used = 0;
40 dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx,
41 s32 poc)
43 struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
44 int i;
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;
54 return 0;
57 int hantro_hevc_add_ref_buf(struct hantro_ctx *ctx, int poc, dma_addr_t addr)
59 struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
60 int i;
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;
72 return -EINVAL;
75 static int tile_buffer_reallocate(struct hantro_ctx *ctx)
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;
86 if (num_tile_cols <= 1 ||
87 num_tile_cols <= hevc_dec->num_tile_cols_allocated)
88 return 0;
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;
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;
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;
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;
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;
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;
136 hevc_dec->num_tile_cols_allocated = num_tile_cols;
138 return 0;
140 err_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;
147 err_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;
154 return -ENOMEM;
157 static int hantro_hevc_validate_sps(struct hantro_ctx *ctx, const struct v4l2_ctrl_hevc_sps *sps)
160 * for tile pixel format check if the width and height match
161 * hardware constraints
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;
168 if (ctx->dst_fmt.height !=
169 ALIGN(sps->pic_height_in_luma_samples, ctx->vpu_dst_fmt->frmsize.step_height))
170 return -EINVAL;
173 return 0;
176 int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx)
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;
182 hantro_start_prepare_run(ctx);
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;
189 ctrls->scaling =
190 hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
191 if (WARN_ON(!ctrls->scaling))
192 return -EINVAL;
194 ctrls->sps =
195 hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_SPS);
196 if (WARN_ON(!ctrls->sps))
197 return -EINVAL;
199 ret = hantro_hevc_validate_sps(ctx, ctrls->sps);
200 if (ret)
201 return ret;
203 ctrls->pps =
204 hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_PPS);
205 if (WARN_ON(!ctrls->pps))
206 return -EINVAL;
208 ret = tile_buffer_reallocate(ctx);
209 if (ret)
210 return ret;
212 return 0;
215 void hantro_hevc_dec_exit(struct hantro_ctx *ctx)
217 struct hantro_dev *vpu = ctx->dev;
218 struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
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;
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;
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;
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;
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;
251 int hantro_hevc_dec_init(struct hantro_ctx *ctx)
253 struct hantro_dev *vpu = ctx->dev;
254 struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
255 unsigned int size;
257 memset(hevc_dec, 0, sizeof(*hevc_dec));
260 * Maximum number of tiles times width and height (2 bytes each),
261 * rounding up to next 16 bytes boundary + one extra 16 byte
262 * chunk (HW guys wanted to have this).
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;
271 hevc_dec->tile_sizes.size = size;
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;
279 hevc_dec->scaling_lists.size = SCALING_LIST_SIZE;
281 hantro_hevc_ref_init(ctx);
283 hevc_dec->use_compression =
284 hevc_use_compression & hantro_needs_postproc(ctx, ctx->vpu_dst_fmt);
286 return 0;