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 } 185 } 186 187 static void parse_max_sessions(struct venus_core *core, const void *data) 188 { 189 const struct hfi_max_sessions_supported *sessions = data; 190 191 core->max_sessions_supported = sessions->max_sessions; 192 } 193 194 static void parse_codecs_mask(u32 *codecs, u32 *domain, void *data) 195 { 196 struct hfi_codec_mask_supported *mask = data; 197 198 *codecs = mask->codecs; 199 *domain = mask->video_domains; 200 } 201 202 static void parser_init(struct venus_inst *inst, u32 *codecs, u32 *domain) 203 { 204 if (!inst || !IS_V1(inst->core)) 205 return; 206 207 *codecs = inst->hfi_codec; 208 *domain = inst->session_type; 209 } 210 211 static void parser_fini(struct venus_inst *inst, u32 codecs, u32 domain) 212 { 213 struct venus_caps *caps, *cap; 214 unsigned int i; 215 u32 dom; 216 217 if (!inst || !IS_V1(inst->core)) 218 return; 219 220 caps = inst->core->caps; 221 dom = inst->session_type; 222 223 for (i = 0; i < MAX_CODEC_NUM; i++) { 224 cap = &caps[i]; 225 if (cap->codec & codecs && cap->domain == dom) 226 cap->valid = true; 227 } 228 } 229 230 u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf, 231 u32 size) 232 { 233 unsigned int words_count = size >> 2; 234 u32 *word = buf, *data, codecs = 0, domain = 0; 235 236 if (size % 4) 237 return HFI_ERR_SYS_INSUFFICIENT_RESOURCES; 238 239 parser_init(inst, &codecs, &domain); 240 241 while (words_count) { 242 data = word + 1; 243 244 switch (*word) { 245 case HFI_PROPERTY_PARAM_CODEC_SUPPORTED: 246 parse_codecs(core, data); 247 init_codecs(core); 248 break; 249 case HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED: 250 parse_max_sessions(core, data); 251 break; 252 case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED: 253 parse_codecs_mask(&codecs, &domain, data); 254 break; 255 case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED: 256 parse_raw_formats(core, codecs, domain, data); 257 break; 258 case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED: 259 parse_caps(core, codecs, domain, data); 260 break; 261 case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED: 262 parse_profile_level(core, codecs, domain, data); 263 break; 264 case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED: 265 parse_alloc_mode(core, codecs, domain, data); 266 break; 267 default: 268 break; 269 } 270 271 word++; 272 words_count--; 273 } 274 275 parser_fini(inst, codecs, domain); 276 277 return HFI_ERR_NONE; 278 } 279