1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2018 Linaro Ltd.
4  *
5  * Author: Stanimir Varbanov <[email protected]>
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 
init_codecs(struct venus_core * core)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 
for_each_codec(struct hfi_plat_caps * caps,unsigned int caps_num,u32 codecs,u32 domain,func cb,void * data,unsigned int size)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
fill_buf_mode(struct hfi_plat_caps * cap,const void * data,unsigned int num)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
parse_alloc_mode(struct venus_core * core,u32 codecs,u32 domain,void * data)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 
fill_profile_level(struct hfi_plat_caps * cap,const void * data,unsigned int num)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
parse_profile_level(struct venus_core * core,u32 codecs,u32 domain,void * data)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
fill_caps(struct hfi_plat_caps * cap,const void * data,unsigned int num)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
parse_caps(struct venus_core * core,u32 codecs,u32 domain,void * data)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 
fill_raw_fmts(struct hfi_plat_caps * cap,const void * fmts,unsigned int num_fmts)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
parse_raw_formats(struct venus_core * core,u32 codecs,u32 domain,void * data)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 
parse_codecs(struct venus_core * core,void * data)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 (IS_V1(core)) {
210 		core->dec_codecs &= ~HFI_VIDEO_CODEC_HEVC;
211 		core->dec_codecs &= ~HFI_VIDEO_CODEC_SPARK;
212 		core->enc_codecs &= ~HFI_VIDEO_CODEC_HEVC;
213 	}
214 
215 	return sizeof(*codecs);
216 }
217 
parse_max_sessions(struct venus_core * core,const void * data)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 
parse_codecs_mask(u32 * codecs,u32 * domain,void * data)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 
parser_init(struct venus_inst * inst,u32 * codecs,u32 * domain)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 
parser_fini(struct venus_inst * inst,u32 codecs,u32 domain)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 
hfi_platform_parser(struct venus_core * core,struct venus_inst * inst)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 	int ret;
272 
273 	plat = hfi_platform_get(core->res->hfi_version);
274 	if (!plat)
275 		return -EINVAL;
276 
277 	if (inst)
278 		return 0;
279 
280 	ret = hfi_platform_get_codecs(core, &enc_codecs, &dec_codecs, &count);
281 	if (ret)
282 		return ret;
283 
284 	if (plat->capabilities)
285 		caps = plat->capabilities(&entries);
286 
287 	if (!caps || !entries || !count)
288 		return -EINVAL;
289 
290 	core->enc_codecs = enc_codecs;
291 	core->dec_codecs = dec_codecs;
292 	core->codecs_count = count;
293 	core->max_sessions_supported = MAX_SESSIONS;
294 	memset(core->caps, 0, sizeof(*caps) * MAX_CODEC_NUM);
295 	memcpy(core->caps, caps, sizeof(*caps) * entries);
296 
297 	return 0;
298 }
299 
hfi_parser(struct venus_core * core,struct venus_inst * inst,void * buf,u32 size)300 u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf,
301 	       u32 size)
302 {
303 	u32 *words = buf, *payload, codecs = 0, domain = 0;
304 	u32 *frame_size = buf + size;
305 	u32 rem_bytes = size;
306 	int ret;
307 
308 	ret = hfi_platform_parser(core, inst);
309 	if (!ret)
310 		return HFI_ERR_NONE;
311 
312 	if (size % 4)
313 		return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
314 
315 	parser_init(inst, &codecs, &domain);
316 
317 	if (core->res->hfi_version > HFI_VERSION_1XX) {
318 		core->codecs_count = 0;
319 		memset(core->caps, 0, sizeof(core->caps));
320 	}
321 
322 	while (words < frame_size) {
323 		payload = words + 1;
324 
325 		switch (*words) {
326 		case HFI_PROPERTY_PARAM_CODEC_SUPPORTED:
327 			if (rem_bytes <= sizeof(struct hfi_codec_supported))
328 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
329 
330 			ret = parse_codecs(core, payload);
331 			if (ret < 0)
332 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
333 
334 			init_codecs(core);
335 			break;
336 		case HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED:
337 			if (rem_bytes <= sizeof(struct hfi_max_sessions_supported))
338 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
339 
340 			ret = parse_max_sessions(core, payload);
341 			break;
342 		case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED:
343 			if (rem_bytes <= sizeof(struct hfi_codec_mask_supported))
344 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
345 
346 			ret = parse_codecs_mask(&codecs, &domain, payload);
347 			break;
348 		case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
349 			if (rem_bytes <= sizeof(struct hfi_uncompressed_format_supported))
350 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
351 
352 			ret = parse_raw_formats(core, codecs, domain, payload);
353 			break;
354 		case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED:
355 			if (rem_bytes <= sizeof(struct hfi_capabilities))
356 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
357 
358 			ret = parse_caps(core, codecs, domain, payload);
359 			break;
360 		case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED:
361 			if (rem_bytes <= sizeof(struct hfi_profile_level_supported))
362 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
363 
364 			ret = parse_profile_level(core, codecs, domain, payload);
365 			break;
366 		case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED:
367 			if (rem_bytes <= sizeof(struct hfi_buffer_alloc_mode_supported))
368 				return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
369 
370 			ret = parse_alloc_mode(core, codecs, domain, payload);
371 			break;
372 		default:
373 			ret = sizeof(u32);
374 			break;
375 		}
376 
377 		if (ret < 0)
378 			return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
379 
380 		words += ret / sizeof(u32);
381 		rem_bytes -= ret;
382 	}
383 
384 	if (!core->max_sessions_supported)
385 		core->max_sessions_supported = MAX_SESSIONS;
386 
387 	parser_fini(inst, codecs, domain);
388 
389 	return HFI_ERR_NONE;
390 }
391