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