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 14 typedef void (*func)(struct hfi_plat_caps *cap, const void *data, 15 unsigned int size); 16 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 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 40 static 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 56 static void 57 fill_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 65 static void 66 parse_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 87 static 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 99 static void 100 parse_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 115 static void 116 fill_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 127 static void 128 parse_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 144 static 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 156 static void 157 parse_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 189 static 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 203 static 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 210 static 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 218 static 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 227 static 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 246 static 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 281 u32 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