xref: /linux/drivers/media/platform/qcom/venus/hfi_parser.c (revision 9cebfe6504488198b012e746bc6b313f88b95439)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2018 Linaro Ltd.
4  *
5  * Author: Stanimir Varbanov <stanimir.varbanov@linaro.org>
6  */
7 #include <linux/bitops.h>
8 #include <linux/kernel.h>
9 
10 #include "core.h"
11 #include "hfi_helper.h"
12 #include "hfi_parser.h"
13 
14 typedef void (*func)(struct hfi_plat_caps *cap, const void *data,
15 		     unsigned int size);
16 
17 static void init_codecs(struct venus_core *core)
18 {
19 	struct hfi_plat_caps *caps = core->caps, *cap;
20 	unsigned long bit;
21 
22 	core->codecs_count = 0;
23 
24 	if (hweight_long(core->dec_codecs) + hweight_long(core->enc_codecs) > MAX_CODEC_NUM)
25 		return;
26 
27 	for_each_set_bit(bit, &core->dec_codecs, MAX_CODEC_NUM) {
28 		cap = &caps[core->codecs_count++];
29 		cap->codec = BIT(bit);
30 		cap->domain = VIDC_SESSION_TYPE_DEC;
31 		cap->valid = false;
32 	}
33 
34 	for_each_set_bit(bit, &core->enc_codecs, MAX_CODEC_NUM) {
35 		cap = &caps[core->codecs_count++];
36 		cap->codec = BIT(bit);
37 		cap->domain = VIDC_SESSION_TYPE_ENC;
38 		cap->valid = false;
39 	}
40 }
41 
42 static void for_each_codec(struct hfi_plat_caps *caps, unsigned int caps_num,
43 			   u32 codecs, u32 domain, func cb, void *data,
44 			   unsigned int size)
45 {
46 	struct hfi_plat_caps *cap;
47 	unsigned int i;
48 
49 	for (i = 0; i < caps_num; i++) {
50 		cap = &caps[i];
51 		if (cap->valid && cap->domain == domain)
52 			continue;
53 		if (cap->codec & codecs && cap->domain == domain)
54 			cb(cap, data, size);
55 	}
56 }
57 
58 static void
59 fill_buf_mode(struct hfi_plat_caps *cap, const void *data, unsigned int num)
60 {
61 	const u32 *type = data;
62 
63 	if (*type == HFI_BUFFER_MODE_DYNAMIC)
64 		cap->cap_bufs_mode_dynamic = true;
65 }
66 
67 static int
68 parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data)
69 {
70 	struct hfi_buffer_alloc_mode_supported *mode = data;
71 	u32 num_entries = mode->num_entries;
72 	u32 *type;
73 
74 	if (num_entries > MAX_ALLOC_MODE_ENTRIES)
75 		return -EINVAL;
76 
77 	type = mode->data;
78 
79 	while (num_entries--) {
80 		if (mode->buffer_type == HFI_BUFFER_OUTPUT ||
81 		    mode->buffer_type == HFI_BUFFER_OUTPUT2)
82 			for_each_codec(core->caps, ARRAY_SIZE(core->caps),
83 				       codecs, domain, fill_buf_mode, type, 1);
84 
85 		type++;
86 	}
87 
88 	return mode->num_entries * sizeof(u32) + sizeof(*mode);
89 }
90 
91 static void fill_profile_level(struct hfi_plat_caps *cap, const void *data,
92 			       unsigned int num)
93 {
94 	const struct hfi_profile_level *pl = data;
95 
96 	if (cap->num_pl + num >= HFI_MAX_PROFILE_COUNT)
97 		return;
98 
99 	memcpy(&cap->pl[cap->num_pl], pl, num * sizeof(*pl));
100 	cap->num_pl += num;
101 }
102 
103 static int
104 parse_profile_level(struct venus_core *core, u32 codecs, u32 domain, void *data)
105 {
106 	struct hfi_profile_level_supported *pl = data;
107 	struct hfi_profile_level *proflevel = pl->profile_level;
108 	struct hfi_profile_level pl_arr[HFI_MAX_PROFILE_COUNT] = {};
109 
110 	if (pl->profile_count > HFI_MAX_PROFILE_COUNT)
111 		return -EINVAL;
112 
113 	memcpy(pl_arr, proflevel, pl->profile_count * sizeof(*proflevel));
114 
115 	for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
116 		       fill_profile_level, pl_arr, pl->profile_count);
117 
118 	return pl->profile_count * sizeof(*proflevel) + sizeof(u32);
119 }
120 
121 static void
122 fill_caps(struct hfi_plat_caps *cap, const void *data, unsigned int num)
123 {
124 	const struct hfi_capability *caps = data;
125 
126 	if (cap->num_caps + num >= MAX_CAP_ENTRIES)
127 		return;
128 
129 	memcpy(&cap->caps[cap->num_caps], caps, num * sizeof(*caps));
130 	cap->num_caps += num;
131 }
132 
133 static int
134 parse_caps(struct venus_core *core, u32 codecs, u32 domain, void *data)
135 {
136 	struct hfi_capabilities *caps = data;
137 	struct hfi_capability *cap = caps->data;
138 	u32 num_caps = caps->num_capabilities;
139 	struct hfi_capability caps_arr[MAX_CAP_ENTRIES] = {};
140 
141 	if (num_caps > MAX_CAP_ENTRIES)
142 		return -EINVAL;
143 
144 	memcpy(caps_arr, cap, num_caps * sizeof(*cap));
145 
146 	for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
147 		       fill_caps, caps_arr, num_caps);
148 
149 	return num_caps * sizeof(*cap) + sizeof(u32);
150 }
151 
152 static void fill_raw_fmts(struct hfi_plat_caps *cap, const void *fmts,
153 			  unsigned int num_fmts)
154 {
155 	const struct raw_formats *formats = fmts;
156 
157 	if (cap->num_fmts + num_fmts >= MAX_FMT_ENTRIES)
158 		return;
159 
160 	memcpy(&cap->fmts[cap->num_fmts], formats, num_fmts * sizeof(*formats));
161 	cap->num_fmts += num_fmts;
162 }
163 
164 static int
165 parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data)
166 {
167 	struct hfi_uncompressed_format_supported *fmt = data;
168 	struct hfi_uncompressed_plane_info *pinfo = &fmt->plane_info;
169 	struct hfi_uncompressed_plane_constraints *constr;
170 	struct raw_formats rawfmts[MAX_FMT_ENTRIES] = {};
171 	u32 entries = fmt->format_entries;
172 	unsigned int i = 0;
173 	u32 num_planes = 0;
174 	u32 size = 2 * sizeof(u32);
175 
176 	while (entries) {
177 		num_planes = pinfo->num_planes;
178 
179 		rawfmts[i].fmt = pinfo->format;
180 		rawfmts[i].buftype = fmt->buffer_type;
181 		i++;
182 
183 		if (i >= MAX_FMT_ENTRIES)
184 			return -EINVAL;
185 
186 		if (pinfo->num_planes > MAX_PLANES)
187 			break;
188 
189 		size += sizeof(*constr) * num_planes + 2 * sizeof(u32);
190 		pinfo = (void *)pinfo + sizeof(*constr) * num_planes +
191 			2 * sizeof(u32);
192 		entries--;
193 	}
194 
195 	for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
196 		       fill_raw_fmts, rawfmts, i);
197 
198 	return size;
199 }
200 
201 static int parse_codecs(struct venus_core *core, void *data)
202 {
203 	struct hfi_codec_supported *codecs = data;
204 
205 	core->dec_codecs = codecs->dec_codecs;
206 	core->enc_codecs = codecs->enc_codecs;
207 
208 	if (core->res->dec_codec_blacklist)
209 		core->dec_codecs &= ~core->res->dec_codec_blacklist;
210 
211 	if (core->res->enc_codec_blacklist)
212 		core->enc_codecs &= ~core->res->enc_codec_blacklist;
213 
214 	return sizeof(*codecs);
215 }
216 
217 static int parse_max_sessions(struct venus_core *core, const void *data)
218 {
219 	const struct hfi_max_sessions_supported *sessions = data;
220 
221 	core->max_sessions_supported = sessions->max_sessions;
222 
223 	return sizeof(*sessions);
224 }
225 
226 static int parse_codecs_mask(u32 *codecs, u32 *domain, void *data)
227 {
228 	struct hfi_codec_mask_supported *mask = data;
229 
230 	*codecs = mask->codecs;
231 	*domain = mask->video_domains;
232 
233 	return sizeof(*mask);
234 }
235 
236 static void parser_init(struct venus_inst *inst, u32 *codecs, u32 *domain)
237 {
238 	if (!inst || !IS_V1(inst->core))
239 		return;
240 
241 	*codecs = inst->hfi_codec;
242 	*domain = inst->session_type;
243 }
244 
245 static void parser_fini(struct venus_inst *inst, u32 codecs, u32 domain)
246 {
247 	struct hfi_plat_caps *caps, *cap;
248 	unsigned int i;
249 	u32 dom;
250 
251 	if (!inst || !IS_V1(inst->core))
252 		return;
253 
254 	caps = inst->core->caps;
255 	dom = inst->session_type;
256 
257 	for (i = 0; i < MAX_CODEC_NUM; i++) {
258 		cap = &caps[i];
259 		if (cap->codec & codecs && cap->domain == dom)
260 			cap->valid = true;
261 	}
262 }
263 
264 static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst)
265 {
266 	const struct hfi_platform *plat;
267 	const struct hfi_plat_caps *caps = NULL;
268 	u32 enc_codecs, dec_codecs, count = 0;
269 	unsigned int entries;
270 
271 	plat = hfi_platform_get(core->res->hfi_version);
272 	if (!plat)
273 		return -EINVAL;
274 
275 	if (inst)
276 		return 0;
277 
278 	if (plat->codecs)
279 		plat->codecs(core, &enc_codecs, &dec_codecs, &count);
280 
281 	if (plat->capabilities)
282 		caps = plat->capabilities(core, &entries);
283 
284 	if (!caps || !entries || !count)
285 		return -EINVAL;
286 
287 	core->enc_codecs = enc_codecs;
288 	core->dec_codecs = dec_codecs;
289 	core->codecs_count = count;
290 	core->max_sessions_supported = MAX_SESSIONS;
291 	memset(core->caps, 0, sizeof(*caps) * MAX_CODEC_NUM);
292 	memcpy(core->caps, caps, sizeof(*caps) * entries);
293 
294 	return 0;
295 }
296 
297 u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf,
298 	       u32 size)
299 {
300 	u32 *words = buf, *payload, codecs = 0, domain = 0;
301 	u32 *frame_size = buf + size;
302 	u32 rem_bytes = size;
303 	int ret;
304 
305 	ret = hfi_platform_parser(core, inst);
306 	if (!ret)
307 		return HFI_ERR_NONE;
308 
309 	if (size % 4)
310 		return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
311 
312 	parser_init(inst, &codecs, &domain);
313 
314 	if (core->res->hfi_version > HFI_VERSION_1XX) {
315 		core->codecs_count = 0;
316 		memset(core->caps, 0, sizeof(core->caps));
317 	}
318 
319 	while (words < frame_size) {
320 		payload = words + 1;
321 
322 		switch (*words) {
323 		case HFI_PROPERTY_PARAM_CODEC_SUPPORTED:
324 			if (rem_bytes <= sizeof(struct hfi_codec_supported))
325 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
326 
327 			ret = parse_codecs(core, payload);
328 			if (ret < 0)
329 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
330 
331 			init_codecs(core);
332 			break;
333 		case HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED:
334 			if (rem_bytes <= sizeof(struct hfi_max_sessions_supported))
335 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
336 
337 			ret = parse_max_sessions(core, payload);
338 			break;
339 		case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED:
340 			if (rem_bytes <= sizeof(struct hfi_codec_mask_supported))
341 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
342 
343 			ret = parse_codecs_mask(&codecs, &domain, payload);
344 			break;
345 		case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
346 			if (rem_bytes <= sizeof(struct hfi_uncompressed_format_supported))
347 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
348 
349 			ret = parse_raw_formats(core, codecs, domain, payload);
350 			break;
351 		case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED:
352 			if (rem_bytes <= sizeof(struct hfi_capabilities))
353 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
354 
355 			ret = parse_caps(core, codecs, domain, payload);
356 			break;
357 		case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED:
358 			if (rem_bytes <= sizeof(struct hfi_profile_level_supported))
359 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
360 
361 			ret = parse_profile_level(core, codecs, domain, payload);
362 			break;
363 		case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED:
364 			if (rem_bytes <= sizeof(struct hfi_buffer_alloc_mode_supported))
365 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
366 
367 			ret = parse_alloc_mode(core, codecs, domain, payload);
368 			break;
369 		default:
370 			ret = sizeof(u32);
371 			break;
372 		}
373 
374 		if (ret < 0)
375 			return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
376 
377 		words += ret / sizeof(u32);
378 		rem_bytes -= ret;
379 	}
380 
381 	if (!core->max_sessions_supported)
382 		core->max_sessions_supported = MAX_SESSIONS;
383 
384 	parser_fini(inst, codecs, domain);
385 
386 	return HFI_ERR_NONE;
387 }
388