File Index
Files and directories
Sign in
FILE

hfi_parser.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/qcom/venus/hfi_parser.c C
  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
 14typedef void (*func)(struct hfi_plat_caps *cap, const void *data,
 15		     unsigned int size);
 16
 17static 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
 42static 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
 58static void
 59fill_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
 67static int
 68parse_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
 91static 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
103static int
104parse_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
121static void
122fill_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
133static int
134parse_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
152static 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
164static int
165parse_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
202static 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
218static 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
227static 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
237static 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
246static 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
265static 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(core, &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
300u32 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}
~/ Read-only file preview.