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 venus_caps *cap, const void *data, 15 unsigned int size); 16 17 static void init_codecs(struct venus_core *core) 18 { 19 struct venus_caps *caps = core->caps, *cap; 20 unsigned long bit; 21 22 for_each_set_bit(bit, &core->dec_codecs, MAX_CODEC_NUM) { 23 cap = &caps[core->codecs_count++]; 24 cap->codec = BIT(bit); 25 cap->domain = VIDC_SESSION_TYPE_DEC; 26 cap->valid = false; 27 } 28 29 for_each_set_bit(bit, &core->enc_codecs, MAX_CODEC_NUM) { 30 cap = &caps[core->codecs_count++]; 31 cap->codec = BIT(bit); 32 cap->domain = VIDC_SESSION_TYPE_ENC; 33 cap->valid = false; 34 } 35 } 36 37 static void for_each_codec(struct venus_caps *caps, unsigned int caps_num, 38 u32 codecs, u32 domain, func cb, void *data, 39 unsigned int size) 40 { 41 struct venus_caps *cap; 42 unsigned int i; 43 44 for (i = 0; i < caps_num; i++) { 45 cap = &caps[i]; 46 if (cap->valid && cap->domain == domain) 47 continue; 48 if (cap->codec & codecs && cap->domain == domain) 49 cb(cap, data, size); 50 } 51 } 52 53 static void 54 fill_buf_mode(struct venus_caps *cap, const void *data, unsigned int num) 55 { 56 const u32 *type = data; 57 58 if (*type == HFI_BUFFER_MODE_DYNAMIC) 59 cap->cap_bufs_mode_dynamic = true; 60 } 61 62 static void 63 parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data) 64 { 65 struct hfi_buffer_alloc_mode_supported *mode = data; 66 u32 num_entries = mode->num_entries; 67 u32 *type; 68 69 if (num_entries > MAX_ALLOC_MODE_ENTRIES) 70 return; 71 72 type = mode->data; 73 74 while (num_entries--) { 75 if (mode->buffer_type == HFI_BUFFER_OUTPUT || 76 mode->buffer_type == HFI_BUFFER_OUTPUT2) 77 for_each_codec(core->caps, ARRAY_SIZE(core->caps), 78 codecs, domain, fill_buf_mode, type, 1); 79 80 type++; 81 } 82 } 83 84 static void fill_profile_level(struct venus_caps *cap, const void *data, 85 unsigned int num) 86 { 87 const struct hfi_profile_level *pl = data; 88 89 memcpy(&cap->pl[cap->num_pl], pl, num * sizeof(*pl)); 90 cap->num_pl += num; 91 } 92 93 static void 94 parse_profile_level(struct venus_core *core, u32 codecs, u32 domain, void *data) 95 { 96 struct hfi_profile_level_supported *pl = data; 97 struct hfi_profile_level *proflevel = pl->profile_level; 98 struct hfi_profile_level pl_arr[HFI_MAX_PROFILE_COUNT] = {}; 99 100 if (pl->profile_count > HFI_MAX_PROFILE_COUNT) 101 return; 102 103 memcpy(pl_arr, proflevel, pl->profile_count * sizeof(*proflevel)); 104 105 for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain, 106 fill_profile_level, pl_arr, pl->profile_count); 107 } 108 109 static void 110 fill_caps(struct venus_caps *cap, const void *data, unsigned int num) 111 { 112 const struct hfi_capability *caps = data; 113 114 memcpy(&cap->caps[cap->num_caps], caps, num * sizeof(*caps)); 115 cap->num_caps += num; 116 } 117 118 static void 119 parse_caps(struct venus_core *core, u32 codecs, u32 domain, void *data) 120 { 121 struct hfi_capabilities *caps = data; 122 struct hfi_capability *cap = caps->data; 123 u32 num_caps = caps->num_capabilities; 124 struct hfi_capability caps_arr[MAX_CAP_ENTRIES] = {}; 125 126 if (num_caps > MAX_CAP_ENTRIES) 127 return; 128 129 memcpy(caps_arr, cap, num_caps * sizeof(*cap)); 130 131 for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain, 132 fill_caps, caps_arr, num_caps); 133 } 134 135 static void fill_raw_fmts(struct venus_caps *cap, const void *fmts, 136 unsigned int num_fmts) 137 { 138 const struct raw_formats *formats = fmts; 139 140 memcpy(&cap->fmts[cap->num_fmts], formats, num_fmts * sizeof(*formats)); 141 cap->num_fmts += num_fmts; 142 } 143 144 static void 145 parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data) 146 { 147 struct hfi_uncompressed_format_supported *fmt = data; 148 struct hfi_uncompressed_plane_info *pinfo = fmt->plane_info; 149 struct hfi_uncompressed_plane_constraints *constr; 150 struct raw_formats rawfmts[MAX_FMT_ENTRIES] = {}; 151 u32 entries = fmt->format_entries; 152 unsigned int i = 0; 153 u32 num_planes; 154 155 while (entries) { 156 num_planes = pinfo->num_planes; 157 158 rawfmts[i].fmt = pinfo->format; 159 rawfmts[i].buftype = fmt->buffer_type; 160 i++; 161 162 if (pinfo->num_planes > MAX_PLANES) 163 break; 164 165 pinfo = (void *)pinfo + sizeof(*constr) * num_planes + 166 2 * sizeof(u32); 167 entries--; 168 } 169 170 for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain, 171 fill_raw_fmts, rawfmts, i); 172 } 173 174 static void parse_codecs(struct venus_core *core, void *data) 175 { 176 struct hfi_codec_supported *codecs = data; 177 178 core->dec_codecs = codecs->dec_codecs; 179 core->enc_codecs = codecs->enc_codecs; 180 181 if (IS_V1(core)) { 182 core->dec_codecs &= ~HFI_VIDEO_CODEC_HEVC; 183 core->dec_codecs &= ~HFI_VIDEO_CODEC_SPARK; 184 core->enc_codecs &= ~HFI_VIDEO_CODEC_HEVC; 185 } 186 } 187 188 static void parse_max_sessions(struct venus_core *core, const void *data) 189 { 190 const struct hfi_max_sessions_supported *sessions = data; 191 192 core->max_sessions_supported = sessions->max_sessions; 193 } 194 195 static void parse_codecs_mask(u32 *codecs, u32 *domain, void *data) 196 { 197 struct hfi_codec_mask_supported *mask = data; 198 199 *codecs = mask->codecs; 200 *domain = mask->video_domains; 201 } 202 203 static void parser_init(struct venus_inst *inst, u32 *codecs, u32 *domain) 204 { 205 if (!inst || !IS_V1(inst->core)) 206 return; 207 208 *codecs = inst->hfi_codec; 209 *domain = inst->session_type; 210 } 211 212 static void parser_fini(struct venus_inst *inst, u32 codecs, u32 domain) 213 { 214 struct venus_caps *caps, *cap; 215 unsigned int i; 216 u32 dom; 217 218 if (!inst || !IS_V1(inst->core)) 219 return; 220 221 caps = inst->core->caps; 222 dom = inst->session_type; 223 224 for (i = 0; i < MAX_CODEC_NUM; i++) { 225 cap = &caps[i]; 226 if (cap->codec & codecs && cap->domain == dom) 227 cap->valid = true; 228 } 229 } 230 231 u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf, 232 u32 size) 233 { 234 unsigned int words_count = size >> 2; 235 u32 *word = buf, *data, codecs = 0, domain = 0; 236 237 if (size % 4) 238 return HFI_ERR_SYS_INSUFFICIENT_RESOURCES; 239 240 parser_init(inst, &codecs, &domain); 241 242 while (words_count) { 243 data = word + 1; 244 245 switch (*word) { 246 case HFI_PROPERTY_PARAM_CODEC_SUPPORTED: 247 parse_codecs(core, data); 248 init_codecs(core); 249 break; 250 case HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED: 251 parse_max_sessions(core, data); 252 break; 253 case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED: 254 parse_codecs_mask(&codecs, &domain, data); 255 break; 256 case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED: 257 parse_raw_formats(core, codecs, domain, data); 258 break; 259 case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED: 260 parse_caps(core, codecs, domain, data); 261 break; 262 case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED: 263 parse_profile_level(core, codecs, domain, data); 264 break; 265 case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED: 266 parse_alloc_mode(core, codecs, domain, data); 267 break; 268 default: 269 break; 270 } 271 272 word++; 273 words_count--; 274 } 275 276 parser_fini(inst, codecs, domain); 277 278 return HFI_ERR_NONE; 279 } 280