xref: /linux/drivers/media/platform/qcom/venus/hfi_parser.c (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
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 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 sizeof(*caps);
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;
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 		pinfo = (void *)pinfo + sizeof(*constr) * num_planes +
190 			2 * sizeof(u32);
191 		entries--;
192 	}
193 
194 	for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
195 		       fill_raw_fmts, rawfmts, i);
196 	size = fmt->format_entries * (sizeof(*constr) * num_planes + 2 * sizeof(u32))
197 		+ 2 * sizeof(u32);
198 
199 	return size;
200 }
201 
202 static int parse_codecs(struct venus_core *core, void *data)
203 {
204 	struct hfi_codec_supported *codecs = data;
205 
206 	core->dec_codecs = codecs->dec_codecs;
207 	core->enc_codecs = codecs->enc_codecs;
208 
209 	if (core->res->dec_codec_blacklist)
210 		core->dec_codecs &= ~core->res->dec_codec_blacklist;
211 
212 	if (core->res->enc_codec_blacklist)
213 		core->enc_codecs &= ~core->res->enc_codec_blacklist;
214 
215 	return sizeof(*codecs);
216 }
217 
218 static int parse_max_sessions(struct venus_core *core, const void *data)
219 {
220 	const struct hfi_max_sessions_supported *sessions = data;
221 
222 	core->max_sessions_supported = sessions->max_sessions;
223 
224 	return sizeof(*sessions);
225 }
226 
227 static int parse_codecs_mask(u32 *codecs, u32 *domain, void *data)
228 {
229 	struct hfi_codec_mask_supported *mask = data;
230 
231 	*codecs = mask->codecs;
232 	*domain = mask->video_domains;
233 
234 	return sizeof(*mask);
235 }
236 
237 static void parser_init(struct venus_inst *inst, u32 *codecs, u32 *domain)
238 {
239 	if (!inst || !IS_V1(inst->core))
240 		return;
241 
242 	*codecs = inst->hfi_codec;
243 	*domain = inst->session_type;
244 }
245 
246 static void parser_fini(struct venus_inst *inst, u32 codecs, u32 domain)
247 {
248 	struct hfi_plat_caps *caps, *cap;
249 	unsigned int i;
250 	u32 dom;
251 
252 	if (!inst || !IS_V1(inst->core))
253 		return;
254 
255 	caps = inst->core->caps;
256 	dom = inst->session_type;
257 
258 	for (i = 0; i < MAX_CODEC_NUM; i++) {
259 		cap = &caps[i];
260 		if (cap->codec & codecs && cap->domain == dom)
261 			cap->valid = true;
262 	}
263 }
264 
265 static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst)
266 {
267 	const struct hfi_platform *plat;
268 	const struct hfi_plat_caps *caps = NULL;
269 	u32 enc_codecs, dec_codecs, count = 0;
270 	unsigned int entries;
271 
272 	plat = hfi_platform_get(core->res->hfi_version);
273 	if (!plat)
274 		return -EINVAL;
275 
276 	if (inst)
277 		return 0;
278 
279 	if (plat->codecs)
280 		plat->codecs(core, &enc_codecs, &dec_codecs, &count);
281 
282 	if (plat->capabilities)
283 		caps = plat->capabilities(core, &entries);
284 
285 	if (!caps || !entries || !count)
286 		return -EINVAL;
287 
288 	core->enc_codecs = enc_codecs;
289 	core->dec_codecs = dec_codecs;
290 	core->codecs_count = count;
291 	core->max_sessions_supported = MAX_SESSIONS;
292 	memset(core->caps, 0, sizeof(*caps) * MAX_CODEC_NUM);
293 	memcpy(core->caps, caps, sizeof(*caps) * entries);
294 
295 	return 0;
296 }
297 
298 u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf,
299 	       u32 size)
300 {
301 	u32 *words = buf, *payload, codecs = 0, domain = 0;
302 	u32 *frame_size = buf + size;
303 	u32 rem_bytes = size;
304 	int ret;
305 
306 	ret = hfi_platform_parser(core, inst);
307 	if (!ret)
308 		return HFI_ERR_NONE;
309 
310 	if (size % 4)
311 		return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
312 
313 	parser_init(inst, &codecs, &domain);
314 
315 	if (core->res->hfi_version > HFI_VERSION_1XX) {
316 		core->codecs_count = 0;
317 		memset(core->caps, 0, sizeof(core->caps));
318 	}
319 
320 	while (words < frame_size) {
321 		payload = words + 1;
322 
323 		switch (*words) {
324 		case HFI_PROPERTY_PARAM_CODEC_SUPPORTED:
325 			if (rem_bytes <= sizeof(struct hfi_codec_supported))
326 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
327 
328 			ret = parse_codecs(core, payload);
329 			if (ret < 0)
330 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
331 
332 			init_codecs(core);
333 			break;
334 		case HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED:
335 			if (rem_bytes <= sizeof(struct hfi_max_sessions_supported))
336 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
337 
338 			ret = parse_max_sessions(core, payload);
339 			break;
340 		case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED:
341 			if (rem_bytes <= sizeof(struct hfi_codec_mask_supported))
342 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
343 
344 			ret = parse_codecs_mask(&codecs, &domain, payload);
345 			break;
346 		case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
347 			if (rem_bytes <= sizeof(struct hfi_uncompressed_format_supported))
348 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
349 
350 			ret = parse_raw_formats(core, codecs, domain, payload);
351 			break;
352 		case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED:
353 			if (rem_bytes <= sizeof(struct hfi_capabilities))
354 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
355 
356 			ret = parse_caps(core, codecs, domain, payload);
357 			break;
358 		case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED:
359 			if (rem_bytes <= sizeof(struct hfi_profile_level_supported))
360 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
361 
362 			ret = parse_profile_level(core, codecs, domain, payload);
363 			break;
364 		case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED:
365 			if (rem_bytes <= sizeof(struct hfi_buffer_alloc_mode_supported))
366 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
367 
368 			ret = parse_alloc_mode(core, codecs, domain, payload);
369 			break;
370 		default:
371 			ret = sizeof(u32);
372 			break;
373 		}
374 
375 		if (ret < 0)
376 			return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
377 
378 		words += ret / sizeof(u32);
379 		rem_bytes -= ret;
380 	}
381 
382 	if (!core->max_sessions_supported)
383 		core->max_sessions_supported = MAX_SESSIONS;
384 
385 	parser_fini(inst, codecs, domain);
386 
387 	return HFI_ERR_NONE;
388 }
389