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