11a73374aSStanimir Varbanov // SPDX-License-Identifier: GPL-2.0
21a73374aSStanimir Varbanov /*
31a73374aSStanimir Varbanov * Copyright (C) 2018 Linaro Ltd.
41a73374aSStanimir Varbanov *
51a73374aSStanimir Varbanov * Author: Stanimir Varbanov <stanimir.varbanov@linaro.org>
61a73374aSStanimir Varbanov */
71a73374aSStanimir Varbanov #include <linux/bitops.h>
81a73374aSStanimir Varbanov #include <linux/kernel.h>
91a73374aSStanimir Varbanov
101a73374aSStanimir Varbanov #include "core.h"
111a73374aSStanimir Varbanov #include "hfi_helper.h"
121a73374aSStanimir Varbanov #include "hfi_parser.h"
131a73374aSStanimir Varbanov
148f3b41dcSStanimir Varbanov typedef void (*func)(struct hfi_plat_caps *cap, const void *data,
151a73374aSStanimir Varbanov unsigned int size);
161a73374aSStanimir Varbanov
init_codecs(struct venus_core * core)171a73374aSStanimir Varbanov static void init_codecs(struct venus_core *core)
181a73374aSStanimir Varbanov {
198f3b41dcSStanimir Varbanov struct hfi_plat_caps *caps = core->caps, *cap;
201a73374aSStanimir Varbanov unsigned long bit;
211a73374aSStanimir Varbanov
2247b12dc2SVikash Garodia if (hweight_long(core->dec_codecs) + hweight_long(core->enc_codecs) > MAX_CODEC_NUM)
2347b12dc2SVikash Garodia return;
2447b12dc2SVikash Garodia
251a73374aSStanimir Varbanov for_each_set_bit(bit, &core->dec_codecs, MAX_CODEC_NUM) {
261a73374aSStanimir Varbanov cap = &caps[core->codecs_count++];
271a73374aSStanimir Varbanov cap->codec = BIT(bit);
281a73374aSStanimir Varbanov cap->domain = VIDC_SESSION_TYPE_DEC;
291a73374aSStanimir Varbanov cap->valid = false;
301a73374aSStanimir Varbanov }
311a73374aSStanimir Varbanov
321a73374aSStanimir Varbanov for_each_set_bit(bit, &core->enc_codecs, MAX_CODEC_NUM) {
331a73374aSStanimir Varbanov cap = &caps[core->codecs_count++];
341a73374aSStanimir Varbanov cap->codec = BIT(bit);
351a73374aSStanimir Varbanov cap->domain = VIDC_SESSION_TYPE_ENC;
361a73374aSStanimir Varbanov cap->valid = false;
371a73374aSStanimir Varbanov }
381a73374aSStanimir Varbanov }
391a73374aSStanimir Varbanov
for_each_codec(struct hfi_plat_caps * caps,unsigned int caps_num,u32 codecs,u32 domain,func cb,void * data,unsigned int size)408f3b41dcSStanimir Varbanov static void for_each_codec(struct hfi_plat_caps *caps, unsigned int caps_num,
411a73374aSStanimir Varbanov u32 codecs, u32 domain, func cb, void *data,
421a73374aSStanimir Varbanov unsigned int size)
431a73374aSStanimir Varbanov {
448f3b41dcSStanimir Varbanov struct hfi_plat_caps *cap;
451a73374aSStanimir Varbanov unsigned int i;
461a73374aSStanimir Varbanov
471a73374aSStanimir Varbanov for (i = 0; i < caps_num; i++) {
481a73374aSStanimir Varbanov cap = &caps[i];
491a73374aSStanimir Varbanov if (cap->valid && cap->domain == domain)
501a73374aSStanimir Varbanov continue;
511a73374aSStanimir Varbanov if (cap->codec & codecs && cap->domain == domain)
521a73374aSStanimir Varbanov cb(cap, data, size);
531a73374aSStanimir Varbanov }
541a73374aSStanimir Varbanov }
551a73374aSStanimir Varbanov
561a73374aSStanimir Varbanov static void
fill_buf_mode(struct hfi_plat_caps * cap,const void * data,unsigned int num)578f3b41dcSStanimir Varbanov fill_buf_mode(struct hfi_plat_caps *cap, const void *data, unsigned int num)
581a73374aSStanimir Varbanov {
591a73374aSStanimir Varbanov const u32 *type = data;
601a73374aSStanimir Varbanov
611a73374aSStanimir Varbanov if (*type == HFI_BUFFER_MODE_DYNAMIC)
621a73374aSStanimir Varbanov cap->cap_bufs_mode_dynamic = true;
631a73374aSStanimir Varbanov }
641a73374aSStanimir Varbanov
651a73374aSStanimir Varbanov static void
parse_alloc_mode(struct venus_core * core,u32 codecs,u32 domain,void * data)66bf26670aSStanimir Varbanov parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data)
671a73374aSStanimir Varbanov {
681a73374aSStanimir Varbanov struct hfi_buffer_alloc_mode_supported *mode = data;
691a73374aSStanimir Varbanov u32 num_entries = mode->num_entries;
701a73374aSStanimir Varbanov u32 *type;
711a73374aSStanimir Varbanov
721a73374aSStanimir Varbanov if (num_entries > MAX_ALLOC_MODE_ENTRIES)
731a73374aSStanimir Varbanov return;
741a73374aSStanimir Varbanov
751a73374aSStanimir Varbanov type = mode->data;
761a73374aSStanimir Varbanov
771a73374aSStanimir Varbanov while (num_entries--) {
781a73374aSStanimir Varbanov if (mode->buffer_type == HFI_BUFFER_OUTPUT ||
79bf26670aSStanimir Varbanov mode->buffer_type == HFI_BUFFER_OUTPUT2)
801a73374aSStanimir Varbanov for_each_codec(core->caps, ARRAY_SIZE(core->caps),
811a73374aSStanimir Varbanov codecs, domain, fill_buf_mode, type, 1);
821a73374aSStanimir Varbanov
831a73374aSStanimir Varbanov type++;
841a73374aSStanimir Varbanov }
851a73374aSStanimir Varbanov }
861a73374aSStanimir Varbanov
fill_profile_level(struct hfi_plat_caps * cap,const void * data,unsigned int num)878f3b41dcSStanimir Varbanov static void fill_profile_level(struct hfi_plat_caps *cap, const void *data,
881a73374aSStanimir Varbanov unsigned int num)
891a73374aSStanimir Varbanov {
901a73374aSStanimir Varbanov const struct hfi_profile_level *pl = data;
911a73374aSStanimir Varbanov
92*648f3945SVikash Garodia if (cap->num_pl + num >= HFI_MAX_PROFILE_COUNT)
93*648f3945SVikash Garodia return;
94*648f3945SVikash Garodia
951a73374aSStanimir Varbanov memcpy(&cap->pl[cap->num_pl], pl, num * sizeof(*pl));
961a73374aSStanimir Varbanov cap->num_pl += num;
971a73374aSStanimir Varbanov }
981a73374aSStanimir Varbanov
991a73374aSStanimir Varbanov static void
parse_profile_level(struct venus_core * core,u32 codecs,u32 domain,void * data)1001a73374aSStanimir Varbanov parse_profile_level(struct venus_core *core, u32 codecs, u32 domain, void *data)
1011a73374aSStanimir Varbanov {
1021a73374aSStanimir Varbanov struct hfi_profile_level_supported *pl = data;
1031a73374aSStanimir Varbanov struct hfi_profile_level *proflevel = pl->profile_level;
1041a73374aSStanimir Varbanov struct hfi_profile_level pl_arr[HFI_MAX_PROFILE_COUNT] = {};
1051a73374aSStanimir Varbanov
1061a73374aSStanimir Varbanov if (pl->profile_count > HFI_MAX_PROFILE_COUNT)
1071a73374aSStanimir Varbanov return;
1081a73374aSStanimir Varbanov
1091a73374aSStanimir Varbanov memcpy(pl_arr, proflevel, pl->profile_count * sizeof(*proflevel));
1101a73374aSStanimir Varbanov
1111a73374aSStanimir Varbanov for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
1121a73374aSStanimir Varbanov fill_profile_level, pl_arr, pl->profile_count);
1131a73374aSStanimir Varbanov }
1141a73374aSStanimir Varbanov
1151a73374aSStanimir Varbanov static void
fill_caps(struct hfi_plat_caps * cap,const void * data,unsigned int num)1168f3b41dcSStanimir Varbanov fill_caps(struct hfi_plat_caps *cap, const void *data, unsigned int num)
1171a73374aSStanimir Varbanov {
1181a73374aSStanimir Varbanov const struct hfi_capability *caps = data;
1191a73374aSStanimir Varbanov
120*648f3945SVikash Garodia if (cap->num_caps + num >= MAX_CAP_ENTRIES)
121*648f3945SVikash Garodia return;
122*648f3945SVikash Garodia
1231a73374aSStanimir Varbanov memcpy(&cap->caps[cap->num_caps], caps, num * sizeof(*caps));
1241a73374aSStanimir Varbanov cap->num_caps += num;
1251a73374aSStanimir Varbanov }
1261a73374aSStanimir Varbanov
1271a73374aSStanimir Varbanov static void
parse_caps(struct venus_core * core,u32 codecs,u32 domain,void * data)1281a73374aSStanimir Varbanov parse_caps(struct venus_core *core, u32 codecs, u32 domain, void *data)
1291a73374aSStanimir Varbanov {
1301a73374aSStanimir Varbanov struct hfi_capabilities *caps = data;
1311a73374aSStanimir Varbanov struct hfi_capability *cap = caps->data;
1321a73374aSStanimir Varbanov u32 num_caps = caps->num_capabilities;
1331a73374aSStanimir Varbanov struct hfi_capability caps_arr[MAX_CAP_ENTRIES] = {};
1341a73374aSStanimir Varbanov
1351a73374aSStanimir Varbanov if (num_caps > MAX_CAP_ENTRIES)
1361a73374aSStanimir Varbanov return;
1371a73374aSStanimir Varbanov
1381a73374aSStanimir Varbanov memcpy(caps_arr, cap, num_caps * sizeof(*cap));
1391a73374aSStanimir Varbanov
1401a73374aSStanimir Varbanov for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
1411a73374aSStanimir Varbanov fill_caps, caps_arr, num_caps);
1421a73374aSStanimir Varbanov }
1431a73374aSStanimir Varbanov
fill_raw_fmts(struct hfi_plat_caps * cap,const void * fmts,unsigned int num_fmts)1448f3b41dcSStanimir Varbanov static void fill_raw_fmts(struct hfi_plat_caps *cap, const void *fmts,
1451a73374aSStanimir Varbanov unsigned int num_fmts)
1461a73374aSStanimir Varbanov {
1471a73374aSStanimir Varbanov const struct raw_formats *formats = fmts;
1481a73374aSStanimir Varbanov
149*648f3945SVikash Garodia if (cap->num_fmts + num_fmts >= MAX_FMT_ENTRIES)
150*648f3945SVikash Garodia return;
151*648f3945SVikash Garodia
1521a73374aSStanimir Varbanov memcpy(&cap->fmts[cap->num_fmts], formats, num_fmts * sizeof(*formats));
1531a73374aSStanimir Varbanov cap->num_fmts += num_fmts;
1541a73374aSStanimir Varbanov }
1551a73374aSStanimir Varbanov
1561a73374aSStanimir Varbanov static void
parse_raw_formats(struct venus_core * core,u32 codecs,u32 domain,void * data)1571a73374aSStanimir Varbanov parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data)
1581a73374aSStanimir Varbanov {
1591a73374aSStanimir Varbanov struct hfi_uncompressed_format_supported *fmt = data;
1601a73374aSStanimir Varbanov struct hfi_uncompressed_plane_info *pinfo = fmt->plane_info;
1611a73374aSStanimir Varbanov struct hfi_uncompressed_plane_constraints *constr;
1621a73374aSStanimir Varbanov struct raw_formats rawfmts[MAX_FMT_ENTRIES] = {};
1631a73374aSStanimir Varbanov u32 entries = fmt->format_entries;
1641a73374aSStanimir Varbanov unsigned int i = 0;
1651a73374aSStanimir Varbanov u32 num_planes;
1661a73374aSStanimir Varbanov
1671a73374aSStanimir Varbanov while (entries) {
1681a73374aSStanimir Varbanov num_planes = pinfo->num_planes;
1691a73374aSStanimir Varbanov
1701a73374aSStanimir Varbanov rawfmts[i].fmt = pinfo->format;
1711a73374aSStanimir Varbanov rawfmts[i].buftype = fmt->buffer_type;
1721a73374aSStanimir Varbanov i++;
1731a73374aSStanimir Varbanov
174*648f3945SVikash Garodia if (i >= MAX_FMT_ENTRIES)
175*648f3945SVikash Garodia return;
176*648f3945SVikash Garodia
1771a73374aSStanimir Varbanov if (pinfo->num_planes > MAX_PLANES)
1781a73374aSStanimir Varbanov break;
1791a73374aSStanimir Varbanov
1801a73374aSStanimir Varbanov pinfo = (void *)pinfo + sizeof(*constr) * num_planes +
1811a73374aSStanimir Varbanov 2 * sizeof(u32);
1821a73374aSStanimir Varbanov entries--;
1831a73374aSStanimir Varbanov }
1841a73374aSStanimir Varbanov
1851a73374aSStanimir Varbanov for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
1861a73374aSStanimir Varbanov fill_raw_fmts, rawfmts, i);
1871a73374aSStanimir Varbanov }
1881a73374aSStanimir Varbanov
parse_codecs(struct venus_core * core,void * data)1891a73374aSStanimir Varbanov static void parse_codecs(struct venus_core *core, void *data)
1901a73374aSStanimir Varbanov {
1911a73374aSStanimir Varbanov struct hfi_codec_supported *codecs = data;
1921a73374aSStanimir Varbanov
1931a73374aSStanimir Varbanov core->dec_codecs = codecs->dec_codecs;
1941a73374aSStanimir Varbanov core->enc_codecs = codecs->enc_codecs;
1951a73374aSStanimir Varbanov
1961a73374aSStanimir Varbanov if (IS_V1(core)) {
1971a73374aSStanimir Varbanov core->dec_codecs &= ~HFI_VIDEO_CODEC_HEVC;
1981a73374aSStanimir Varbanov core->dec_codecs &= ~HFI_VIDEO_CODEC_SPARK;
199c50cc6dcSStephan Gerhold core->enc_codecs &= ~HFI_VIDEO_CODEC_HEVC;
2001a73374aSStanimir Varbanov }
2011a73374aSStanimir Varbanov }
2021a73374aSStanimir Varbanov
parse_max_sessions(struct venus_core * core,const void * data)2031a73374aSStanimir Varbanov static void parse_max_sessions(struct venus_core *core, const void *data)
2041a73374aSStanimir Varbanov {
2051a73374aSStanimir Varbanov const struct hfi_max_sessions_supported *sessions = data;
2061a73374aSStanimir Varbanov
2071a73374aSStanimir Varbanov core->max_sessions_supported = sessions->max_sessions;
2081a73374aSStanimir Varbanov }
2091a73374aSStanimir Varbanov
parse_codecs_mask(u32 * codecs,u32 * domain,void * data)2101a73374aSStanimir Varbanov static void parse_codecs_mask(u32 *codecs, u32 *domain, void *data)
2111a73374aSStanimir Varbanov {
2121a73374aSStanimir Varbanov struct hfi_codec_mask_supported *mask = data;
2131a73374aSStanimir Varbanov
2141a73374aSStanimir Varbanov *codecs = mask->codecs;
2151a73374aSStanimir Varbanov *domain = mask->video_domains;
2161a73374aSStanimir Varbanov }
2171a73374aSStanimir Varbanov
parser_init(struct venus_inst * inst,u32 * codecs,u32 * domain)2181a73374aSStanimir Varbanov static void parser_init(struct venus_inst *inst, u32 *codecs, u32 *domain)
2191a73374aSStanimir Varbanov {
2201a73374aSStanimir Varbanov if (!inst || !IS_V1(inst->core))
2211a73374aSStanimir Varbanov return;
2221a73374aSStanimir Varbanov
2231a73374aSStanimir Varbanov *codecs = inst->hfi_codec;
2241a73374aSStanimir Varbanov *domain = inst->session_type;
2251a73374aSStanimir Varbanov }
2261a73374aSStanimir Varbanov
parser_fini(struct venus_inst * inst,u32 codecs,u32 domain)2271a73374aSStanimir Varbanov static void parser_fini(struct venus_inst *inst, u32 codecs, u32 domain)
2281a73374aSStanimir Varbanov {
2298f3b41dcSStanimir Varbanov struct hfi_plat_caps *caps, *cap;
2301a73374aSStanimir Varbanov unsigned int i;
2311a73374aSStanimir Varbanov u32 dom;
2321a73374aSStanimir Varbanov
2331a73374aSStanimir Varbanov if (!inst || !IS_V1(inst->core))
2341a73374aSStanimir Varbanov return;
2351a73374aSStanimir Varbanov
2361a73374aSStanimir Varbanov caps = inst->core->caps;
2371a73374aSStanimir Varbanov dom = inst->session_type;
2381a73374aSStanimir Varbanov
2391a73374aSStanimir Varbanov for (i = 0; i < MAX_CODEC_NUM; i++) {
2401a73374aSStanimir Varbanov cap = &caps[i];
2411a73374aSStanimir Varbanov if (cap->codec & codecs && cap->domain == dom)
2421a73374aSStanimir Varbanov cap->valid = true;
2431a73374aSStanimir Varbanov }
2441a73374aSStanimir Varbanov }
2451a73374aSStanimir Varbanov
hfi_platform_parser(struct venus_core * core,struct venus_inst * inst)246e2992926SStanimir Varbanov static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst)
247e2992926SStanimir Varbanov {
248e2992926SStanimir Varbanov const struct hfi_platform *plat;
249e2992926SStanimir Varbanov const struct hfi_plat_caps *caps = NULL;
250c5b14df7SColin Ian King u32 enc_codecs, dec_codecs, count = 0;
251e2992926SStanimir Varbanov unsigned int entries;
252c0ab2901SVikash Garodia int ret;
253e2992926SStanimir Varbanov
254e2992926SStanimir Varbanov plat = hfi_platform_get(core->res->hfi_version);
255e2992926SStanimir Varbanov if (!plat)
256e2992926SStanimir Varbanov return -EINVAL;
257e2992926SStanimir Varbanov
2589b5d8fd5SStanimir Varbanov if (inst)
2599b5d8fd5SStanimir Varbanov return 0;
2609b5d8fd5SStanimir Varbanov
261c0ab2901SVikash Garodia ret = hfi_platform_get_codecs(core, &enc_codecs, &dec_codecs, &count);
262c0ab2901SVikash Garodia if (ret)
263c0ab2901SVikash Garodia return ret;
264e2992926SStanimir Varbanov
265e2992926SStanimir Varbanov if (plat->capabilities)
266e2992926SStanimir Varbanov caps = plat->capabilities(&entries);
267e2992926SStanimir Varbanov
268e2992926SStanimir Varbanov if (!caps || !entries || !count)
269e2992926SStanimir Varbanov return -EINVAL;
270e2992926SStanimir Varbanov
271e2992926SStanimir Varbanov core->enc_codecs = enc_codecs;
272e2992926SStanimir Varbanov core->dec_codecs = dec_codecs;
273e2992926SStanimir Varbanov core->codecs_count = count;
274e2992926SStanimir Varbanov core->max_sessions_supported = MAX_SESSIONS;
275e2992926SStanimir Varbanov memset(core->caps, 0, sizeof(*caps) * MAX_CODEC_NUM);
276e2992926SStanimir Varbanov memcpy(core->caps, caps, sizeof(*caps) * entries);
277e2992926SStanimir Varbanov
278e2992926SStanimir Varbanov return 0;
279e2992926SStanimir Varbanov }
280e2992926SStanimir Varbanov
hfi_parser(struct venus_core * core,struct venus_inst * inst,void * buf,u32 size)2811a73374aSStanimir Varbanov u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf,
2821a73374aSStanimir Varbanov u32 size)
2831a73374aSStanimir Varbanov {
2841a73374aSStanimir Varbanov unsigned int words_count = size >> 2;
2851a73374aSStanimir Varbanov u32 *word = buf, *data, codecs = 0, domain = 0;
286e2992926SStanimir Varbanov int ret;
287e2992926SStanimir Varbanov
288e2992926SStanimir Varbanov ret = hfi_platform_parser(core, inst);
289e2992926SStanimir Varbanov if (!ret)
290e2992926SStanimir Varbanov return HFI_ERR_NONE;
2911a73374aSStanimir Varbanov
2921a73374aSStanimir Varbanov if (size % 4)
2931a73374aSStanimir Varbanov return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
2941a73374aSStanimir Varbanov
2951a73374aSStanimir Varbanov parser_init(inst, &codecs, &domain);
2961a73374aSStanimir Varbanov
297834124c5SStanimir Varbanov if (core->res->hfi_version > HFI_VERSION_1XX) {
29810865c98SStanimir Varbanov core->codecs_count = 0;
29910865c98SStanimir Varbanov memset(core->caps, 0, sizeof(core->caps));
300834124c5SStanimir Varbanov }
30110865c98SStanimir Varbanov
3021a73374aSStanimir Varbanov while (words_count) {
3031a73374aSStanimir Varbanov data = word + 1;
3041a73374aSStanimir Varbanov
3051a73374aSStanimir Varbanov switch (*word) {
3061a73374aSStanimir Varbanov case HFI_PROPERTY_PARAM_CODEC_SUPPORTED:
3071a73374aSStanimir Varbanov parse_codecs(core, data);
3081a73374aSStanimir Varbanov init_codecs(core);
3091a73374aSStanimir Varbanov break;
3101a73374aSStanimir Varbanov case HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED:
3111a73374aSStanimir Varbanov parse_max_sessions(core, data);
3121a73374aSStanimir Varbanov break;
3131a73374aSStanimir Varbanov case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED:
3141a73374aSStanimir Varbanov parse_codecs_mask(&codecs, &domain, data);
3151a73374aSStanimir Varbanov break;
3161a73374aSStanimir Varbanov case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
3171a73374aSStanimir Varbanov parse_raw_formats(core, codecs, domain, data);
3181a73374aSStanimir Varbanov break;
3191a73374aSStanimir Varbanov case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED:
3201a73374aSStanimir Varbanov parse_caps(core, codecs, domain, data);
3211a73374aSStanimir Varbanov break;
3221a73374aSStanimir Varbanov case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED:
3231a73374aSStanimir Varbanov parse_profile_level(core, codecs, domain, data);
3241a73374aSStanimir Varbanov break;
3251a73374aSStanimir Varbanov case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED:
326bf26670aSStanimir Varbanov parse_alloc_mode(core, codecs, domain, data);
3271a73374aSStanimir Varbanov break;
3281a73374aSStanimir Varbanov default:
3291a73374aSStanimir Varbanov break;
3301a73374aSStanimir Varbanov }
3311a73374aSStanimir Varbanov
3321a73374aSStanimir Varbanov word++;
3331a73374aSStanimir Varbanov words_count--;
3341a73374aSStanimir Varbanov }
3351a73374aSStanimir Varbanov
33620891170SStanimir Varbanov if (!core->max_sessions_supported)
33720891170SStanimir Varbanov core->max_sessions_supported = MAX_SESSIONS;
33820891170SStanimir Varbanov
3391a73374aSStanimir Varbanov parser_fini(inst, codecs, domain);
3401a73374aSStanimir Varbanov
3411a73374aSStanimir Varbanov return HFI_ERR_NONE;
3421a73374aSStanimir Varbanov }
343