brintos

brintos / linux-shallow public Read only

0
0
Text · 8.1 KiB · 3df241d Raw
343 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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	if (hweight_long(core->dec_codecs) + hweight_long(core->enc_codecs) > MAX_CODEC_NUM)23		return;24 25	for_each_set_bit(bit, &core->dec_codecs, MAX_CODEC_NUM) {26		cap = &caps[core->codecs_count++];27		cap->codec = BIT(bit);28		cap->domain = VIDC_SESSION_TYPE_DEC;29		cap->valid = false;30	}31 32	for_each_set_bit(bit, &core->enc_codecs, MAX_CODEC_NUM) {33		cap = &caps[core->codecs_count++];34		cap->codec = BIT(bit);35		cap->domain = VIDC_SESSION_TYPE_ENC;36		cap->valid = false;37	}38}39 40static void for_each_codec(struct hfi_plat_caps *caps, unsigned int caps_num,41			   u32 codecs, u32 domain, func cb, void *data,42			   unsigned int size)43{44	struct hfi_plat_caps *cap;45	unsigned int i;46 47	for (i = 0; i < caps_num; i++) {48		cap = &caps[i];49		if (cap->valid && cap->domain == domain)50			continue;51		if (cap->codec & codecs && cap->domain == domain)52			cb(cap, data, size);53	}54}55 56static void57fill_buf_mode(struct hfi_plat_caps *cap, const void *data, unsigned int num)58{59	const u32 *type = data;60 61	if (*type == HFI_BUFFER_MODE_DYNAMIC)62		cap->cap_bufs_mode_dynamic = true;63}64 65static void66parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data)67{68	struct hfi_buffer_alloc_mode_supported *mode = data;69	u32 num_entries = mode->num_entries;70	u32 *type;71 72	if (num_entries > MAX_ALLOC_MODE_ENTRIES)73		return;74 75	type = mode->data;76 77	while (num_entries--) {78		if (mode->buffer_type == HFI_BUFFER_OUTPUT ||79		    mode->buffer_type == HFI_BUFFER_OUTPUT2)80			for_each_codec(core->caps, ARRAY_SIZE(core->caps),81				       codecs, domain, fill_buf_mode, type, 1);82 83		type++;84	}85}86 87static void fill_profile_level(struct hfi_plat_caps *cap, const void *data,88			       unsigned int num)89{90	const struct hfi_profile_level *pl = data;91 92	if (cap->num_pl + num >= HFI_MAX_PROFILE_COUNT)93		return;94 95	memcpy(&cap->pl[cap->num_pl], pl, num * sizeof(*pl));96	cap->num_pl += num;97}98 99static void100parse_profile_level(struct venus_core *core, u32 codecs, u32 domain, void *data)101{102	struct hfi_profile_level_supported *pl = data;103	struct hfi_profile_level *proflevel = pl->profile_level;104	struct hfi_profile_level pl_arr[HFI_MAX_PROFILE_COUNT] = {};105 106	if (pl->profile_count > HFI_MAX_PROFILE_COUNT)107		return;108 109	memcpy(pl_arr, proflevel, pl->profile_count * sizeof(*proflevel));110 111	for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,112		       fill_profile_level, pl_arr, pl->profile_count);113}114 115static void116fill_caps(struct hfi_plat_caps *cap, const void *data, unsigned int num)117{118	const struct hfi_capability *caps = data;119 120	if (cap->num_caps + num >= MAX_CAP_ENTRIES)121		return;122 123	memcpy(&cap->caps[cap->num_caps], caps, num * sizeof(*caps));124	cap->num_caps += num;125}126 127static void128parse_caps(struct venus_core *core, u32 codecs, u32 domain, void *data)129{130	struct hfi_capabilities *caps = data;131	struct hfi_capability *cap = caps->data;132	u32 num_caps = caps->num_capabilities;133	struct hfi_capability caps_arr[MAX_CAP_ENTRIES] = {};134 135	if (num_caps > MAX_CAP_ENTRIES)136		return;137 138	memcpy(caps_arr, cap, num_caps * sizeof(*cap));139 140	for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,141		       fill_caps, caps_arr, num_caps);142}143 144static void fill_raw_fmts(struct hfi_plat_caps *cap, const void *fmts,145			  unsigned int num_fmts)146{147	const struct raw_formats *formats = fmts;148 149	if (cap->num_fmts + num_fmts >= MAX_FMT_ENTRIES)150		return;151 152	memcpy(&cap->fmts[cap->num_fmts], formats, num_fmts * sizeof(*formats));153	cap->num_fmts += num_fmts;154}155 156static void157parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data)158{159	struct hfi_uncompressed_format_supported *fmt = data;160	struct hfi_uncompressed_plane_info *pinfo = &fmt->plane_info;161	struct hfi_uncompressed_plane_constraints *constr;162	struct raw_formats rawfmts[MAX_FMT_ENTRIES] = {};163	u32 entries = fmt->format_entries;164	unsigned int i = 0;165	u32 num_planes;166 167	while (entries) {168		num_planes = pinfo->num_planes;169 170		rawfmts[i].fmt = pinfo->format;171		rawfmts[i].buftype = fmt->buffer_type;172		i++;173 174		if (i >= MAX_FMT_ENTRIES)175			return;176 177		if (pinfo->num_planes > MAX_PLANES)178			break;179 180		pinfo = (void *)pinfo + sizeof(*constr) * num_planes +181			2 * sizeof(u32);182		entries--;183	}184 185	for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,186		       fill_raw_fmts, rawfmts, i);187}188 189static void parse_codecs(struct venus_core *core, void *data)190{191	struct hfi_codec_supported *codecs = data;192 193	core->dec_codecs = codecs->dec_codecs;194	core->enc_codecs = codecs->enc_codecs;195 196	if (IS_V1(core)) {197		core->dec_codecs &= ~HFI_VIDEO_CODEC_HEVC;198		core->dec_codecs &= ~HFI_VIDEO_CODEC_SPARK;199		core->enc_codecs &= ~HFI_VIDEO_CODEC_HEVC;200	}201}202 203static void parse_max_sessions(struct venus_core *core, const void *data)204{205	const struct hfi_max_sessions_supported *sessions = data;206 207	core->max_sessions_supported = sessions->max_sessions;208}209 210static void parse_codecs_mask(u32 *codecs, u32 *domain, void *data)211{212	struct hfi_codec_mask_supported *mask = data;213 214	*codecs = mask->codecs;215	*domain = mask->video_domains;216}217 218static void parser_init(struct venus_inst *inst, u32 *codecs, u32 *domain)219{220	if (!inst || !IS_V1(inst->core))221		return;222 223	*codecs = inst->hfi_codec;224	*domain = inst->session_type;225}226 227static void parser_fini(struct venus_inst *inst, u32 codecs, u32 domain)228{229	struct hfi_plat_caps *caps, *cap;230	unsigned int i;231	u32 dom;232 233	if (!inst || !IS_V1(inst->core))234		return;235 236	caps = inst->core->caps;237	dom = inst->session_type;238 239	for (i = 0; i < MAX_CODEC_NUM; i++) {240		cap = &caps[i];241		if (cap->codec & codecs && cap->domain == dom)242			cap->valid = true;243	}244}245 246static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst)247{248	const struct hfi_platform *plat;249	const struct hfi_plat_caps *caps = NULL;250	u32 enc_codecs, dec_codecs, count = 0;251	unsigned int entries;252	int ret;253 254	plat = hfi_platform_get(core->res->hfi_version);255	if (!plat)256		return -EINVAL;257 258	if (inst)259		return 0;260 261	ret = hfi_platform_get_codecs(core, &enc_codecs, &dec_codecs, &count);262	if (ret)263		return ret;264 265	if (plat->capabilities)266		caps = plat->capabilities(&entries);267 268	if (!caps || !entries || !count)269		return -EINVAL;270 271	core->enc_codecs = enc_codecs;272	core->dec_codecs = dec_codecs;273	core->codecs_count = count;274	core->max_sessions_supported = MAX_SESSIONS;275	memset(core->caps, 0, sizeof(*caps) * MAX_CODEC_NUM);276	memcpy(core->caps, caps, sizeof(*caps) * entries);277 278	return 0;279}280 281u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf,282	       u32 size)283{284	unsigned int words_count = size >> 2;285	u32 *word = buf, *data, codecs = 0, domain = 0;286	int ret;287 288	ret = hfi_platform_parser(core, inst);289	if (!ret)290		return HFI_ERR_NONE;291 292	if (size % 4)293		return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;294 295	parser_init(inst, &codecs, &domain);296 297	if (core->res->hfi_version > HFI_VERSION_1XX) {298		core->codecs_count = 0;299		memset(core->caps, 0, sizeof(core->caps));300	}301 302	while (words_count) {303		data = word + 1;304 305		switch (*word) {306		case HFI_PROPERTY_PARAM_CODEC_SUPPORTED:307			parse_codecs(core, data);308			init_codecs(core);309			break;310		case HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED:311			parse_max_sessions(core, data);312			break;313		case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED:314			parse_codecs_mask(&codecs, &domain, data);315			break;316		case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:317			parse_raw_formats(core, codecs, domain, data);318			break;319		case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED:320			parse_caps(core, codecs, domain, data);321			break;322		case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED:323			parse_profile_level(core, codecs, domain, data);324			break;325		case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED:326			parse_alloc_mode(core, codecs, domain, data);327			break;328		default:329			break;330		}331 332		word++;333		words_count--;334	}335 336	if (!core->max_sessions_supported)337		core->max_sessions_supported = MAX_SESSIONS;338 339	parser_fini(inst, codecs, domain);340 341	return HFI_ERR_NONE;342}343