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