199100Siedowse// SPDX-License-Identifier: GPL-2.0-only OR MIT
299100Siedowse/* Copyright 2021 Alyssa Rosenzweig <alyssa@rosenzweig.io> */
3319182Sngie
499100Siedowse#include <linux/kernel.h>
599100Siedowse#include <linux/err.h>
6219804Skib#include <linux/math.h>
7116754Siedowse#include <linux/string.h>
8163851Spjd#include <linux/slab.h>
9267226Skib
10267226Skib#include <sound/pcm.h> // for sound format masks
11267226Skib
1299100Siedowse#include "parser.h"
13165450Syar#include "trace.h"
1499100Siedowse
15165450Syar#define DCP_PARSE_HEADER 0xd3
1699100Siedowse
1799100Siedowseenum dcp_parse_type {
18	DCP_TYPE_DICTIONARY = 1,
19	DCP_TYPE_ARRAY = 2,
20	DCP_TYPE_INT64 = 4,
21	DCP_TYPE_STRING = 9,
22	DCP_TYPE_BLOB = 10,
23	DCP_TYPE_BOOL = 11
24};
25
26struct dcp_parse_tag {
27	unsigned int size : 24;
28	enum dcp_parse_type type : 5;
29	unsigned int padding : 2;
30	bool last : 1;
31} __packed;
32
33static const void *parse_bytes(struct dcp_parse_ctx *ctx, size_t count)
34{
35	const void *ptr = ctx->blob + ctx->pos;
36
37	if (ctx->pos + count > ctx->len)
38		return ERR_PTR(-EINVAL);
39
40	ctx->pos += count;
41	return ptr;
42}
43
44static const u32 *parse_u32(struct dcp_parse_ctx *ctx)
45{
46	return parse_bytes(ctx, sizeof(u32));
47}
48
49static const struct dcp_parse_tag *parse_tag(struct dcp_parse_ctx *ctx)
50{
51	const struct dcp_parse_tag *tag;
52
53	/* Align to 32-bits */
54	ctx->pos = round_up(ctx->pos, 4);
55
56	tag = parse_bytes(ctx, sizeof(struct dcp_parse_tag));
57
58	if (IS_ERR(tag))
59		return tag;
60
61	if (tag->padding)
62		return ERR_PTR(-EINVAL);
63
64	return tag;
65}
66
67static const struct dcp_parse_tag *parse_tag_of_type(struct dcp_parse_ctx *ctx,
68					       enum dcp_parse_type type)
69{
70	const struct dcp_parse_tag *tag = parse_tag(ctx);
71
72	if (IS_ERR(tag))
73		return tag;
74
75	if (tag->type != type)
76		return ERR_PTR(-EINVAL);
77
78	return tag;
79}
80
81static int skip(struct dcp_parse_ctx *handle)
82{
83	const struct dcp_parse_tag *tag = parse_tag(handle);
84	int ret = 0;
85	int i;
86
87	if (IS_ERR(tag))
88		return PTR_ERR(tag);
89
90	switch (tag->type) {
91	case DCP_TYPE_DICTIONARY:
92		for (i = 0; i < tag->size; ++i) {
93			ret |= skip(handle); /* key */
94			ret |= skip(handle); /* value */
95		}
96
97		return ret;
98
99	case DCP_TYPE_ARRAY:
100		for (i = 0; i < tag->size; ++i)
101			ret |= skip(handle);
102
103		return ret;
104
105	case DCP_TYPE_INT64:
106		handle->pos += sizeof(s64);
107		return 0;
108
109	case DCP_TYPE_STRING:
110	case DCP_TYPE_BLOB:
111		handle->pos += tag->size;
112		return 0;
113
114	case DCP_TYPE_BOOL:
115		return 0;
116
117	default:
118		return -EINVAL;
119	}
120}
121
122static int skip_pair(struct dcp_parse_ctx *handle)
123{
124	int ret;
125
126	ret = skip(handle);
127	if (ret)
128		return ret;
129
130	return skip(handle);
131}
132
133static bool consume_string(struct dcp_parse_ctx *ctx, const char *specimen)
134{
135	const struct dcp_parse_tag *tag;
136	const char *key;
137	ctx->pos = round_up(ctx->pos, 4);
138
139	if (ctx->pos + sizeof(*tag) + strlen(specimen) - 1 > ctx->len)
140		return false;
141	tag = ctx->blob + ctx->pos;
142	key = ctx->blob + ctx->pos + sizeof(*tag);
143	if (tag->padding)
144		return false;
145
146	if (tag->type != DCP_TYPE_STRING ||
147	    tag->size != strlen(specimen) ||
148	    strncmp(key, specimen, tag->size))
149		return false;
150
151	skip(ctx);
152	return true;
153}
154
155/* Caller must free the result */
156static char *parse_string(struct dcp_parse_ctx *handle)
157{
158	const struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_STRING);
159	const char *in;
160	char *out;
161
162	if (IS_ERR(tag))
163		return (void *)tag;
164
165	in = parse_bytes(handle, tag->size);
166	if (IS_ERR(in))
167		return (void *)in;
168
169	out = kmalloc(tag->size + 1, GFP_KERNEL);
170
171	memcpy(out, in, tag->size);
172	out[tag->size] = '\0';
173	return out;
174}
175
176static int parse_int(struct dcp_parse_ctx *handle, s64 *value)
177{
178	const void *tag = parse_tag_of_type(handle, DCP_TYPE_INT64);
179	const s64 *in;
180
181	if (IS_ERR(tag))
182		return PTR_ERR(tag);
183
184	in = parse_bytes(handle, sizeof(s64));
185
186	if (IS_ERR(in))
187		return PTR_ERR(in);
188
189	memcpy(value, in, sizeof(*value));
190	return 0;
191}
192
193static int parse_bool(struct dcp_parse_ctx *handle, bool *b)
194{
195	const struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_BOOL);
196
197	if (IS_ERR(tag))
198		return PTR_ERR(tag);
199
200	*b = !!tag->size;
201	return 0;
202}
203
204static int parse_blob(struct dcp_parse_ctx *handle, size_t size, u8 const **blob)
205{
206	const struct dcp_parse_tag *tag = parse_tag_of_type(handle, DCP_TYPE_BLOB);
207	const u8 *out;
208
209	if (IS_ERR(tag))
210		return PTR_ERR(tag);
211
212	if (tag->size < size)
213		return -EINVAL;
214
215	out = parse_bytes(handle, tag->size);
216
217	if (IS_ERR(out))
218		return PTR_ERR(out);
219
220	*blob = out;
221	return 0;
222}
223
224struct iterator {
225	struct dcp_parse_ctx *handle;
226	u32 idx, len;
227};
228
229static int iterator_begin(struct dcp_parse_ctx *handle, struct iterator *it,
230			  bool dict)
231{
232	const struct dcp_parse_tag *tag;
233	enum dcp_parse_type type = dict ? DCP_TYPE_DICTIONARY : DCP_TYPE_ARRAY;
234
235	*it = (struct iterator) {
236		.handle = handle,
237		.idx = 0
238	};
239
240	tag = parse_tag_of_type(it->handle, type);
241	if (IS_ERR(tag))
242		return PTR_ERR(tag);
243
244	it->len = tag->size;
245	return 0;
246}
247
248#define dcp_parse_foreach_in_array(handle, it)                                 \
249	for (iterator_begin(handle, &it, false); it.idx < it.len; ++it.idx)
250#define dcp_parse_foreach_in_dict(handle, it)                                  \
251	for (iterator_begin(handle, &it, true); it.idx < it.len; ++it.idx)
252
253int parse(const void *blob, size_t size, struct dcp_parse_ctx *ctx)
254{
255	const u32 *header;
256
257	*ctx = (struct dcp_parse_ctx) {
258		.blob = blob,
259		.len = size,
260		.pos = 0,
261	};
262
263	header = parse_u32(ctx);
264	if (IS_ERR(header))
265		return PTR_ERR(header);
266
267	if (*header != DCP_PARSE_HEADER)
268		return -EINVAL;
269
270	return 0;
271}
272
273static int parse_dimension(struct dcp_parse_ctx *handle, struct dimension *dim)
274{
275	struct iterator it;
276	int ret = 0;
277
278	dcp_parse_foreach_in_dict(handle, it) {
279		char *key = parse_string(it.handle);
280
281		if (IS_ERR(key))
282			ret = PTR_ERR(key);
283		else if (!strcmp(key, "Active"))
284			ret = parse_int(it.handle, &dim->active);
285		else if (!strcmp(key, "Total"))
286			ret = parse_int(it.handle, &dim->total);
287		else if (!strcmp(key, "FrontPorch"))
288			ret = parse_int(it.handle, &dim->front_porch);
289		else if (!strcmp(key, "SyncWidth"))
290			ret = parse_int(it.handle, &dim->sync_width);
291		else if (!strcmp(key, "PreciseSyncRate"))
292			ret = parse_int(it.handle, &dim->precise_sync_rate);
293		else
294			skip(it.handle);
295
296		if (!IS_ERR_OR_NULL(key))
297			kfree(key);
298
299		if (ret)
300			return ret;
301	}
302
303	return 0;
304}
305
306struct color_mode {
307	s64 colorimetry;
308	s64 depth;
309	s64 dynamic_range;
310	s64 eotf;
311	s64 id;
312	s64 pixel_encoding;
313	s64 score;
314};
315
316static int fill_color_mode(struct dcp_color_mode *color,
317			   struct color_mode *cmode)
318{
319	if (color->score >= cmode->score)
320		return 0;
321
322	if (cmode->colorimetry < 0 || cmode->colorimetry >= DCP_COLORIMETRY_COUNT)
323		return -EINVAL;
324	if (cmode->depth < 8 || cmode->depth > 12)
325		return -EINVAL;
326	if (cmode->dynamic_range < 0 || cmode->dynamic_range >= DCP_COLOR_YCBCR_RANGE_COUNT)
327		return -EINVAL;
328	if (cmode->eotf < 0 || cmode->eotf >= DCP_EOTF_COUNT)
329		return -EINVAL;
330	if (cmode->pixel_encoding < 0 || cmode->pixel_encoding >= DCP_COLOR_FORMAT_COUNT)
331		return -EINVAL;
332
333	color->score = cmode->score;
334	color->id = cmode->id;
335	color->eotf = cmode->eotf;
336	color->format = cmode->pixel_encoding;
337	color->colorimetry = cmode->colorimetry;
338	color->range = cmode->dynamic_range;
339	color->depth = cmode->depth;
340
341	return 0;
342}
343
344static int parse_color_modes(struct dcp_parse_ctx *handle,
345			     struct dcp_display_mode *out)
346{
347	struct iterator outer_it;
348	int ret = 0;
349	out->sdr_444.score = -1;
350	out->sdr_rgb.score = -1;
351	out->best.score = -1;
352
353	dcp_parse_foreach_in_array(handle, outer_it) {
354		struct iterator it;
355		bool is_virtual = true;
356		struct color_mode cmode;
357
358		dcp_parse_foreach_in_dict(handle, it) {
359			char *key = parse_string(it.handle);
360
361			if (IS_ERR(key))
362				ret = PTR_ERR(key);
363			else if (!strcmp(key, "Colorimetry"))
364				ret = parse_int(it.handle, &cmode.colorimetry);
365			else if (!strcmp(key, "Depth"))
366				ret = parse_int(it.handle, &cmode.depth);
367			else if (!strcmp(key, "DynamicRange"))
368				ret = parse_int(it.handle, &cmode.dynamic_range);
369			else if (!strcmp(key, "EOTF"))
370				ret = parse_int(it.handle, &cmode.eotf);
371			else if (!strcmp(key, "ID"))
372				ret = parse_int(it.handle, &cmode.id);
373			else if (!strcmp(key, "IsVirtual"))
374				ret = parse_bool(it.handle, &is_virtual);
375			else if (!strcmp(key, "PixelEncoding"))
376				ret = parse_int(it.handle, &cmode.pixel_encoding);
377			else if (!strcmp(key, "Score"))
378				ret = parse_int(it.handle, &cmode.score);
379			else
380				skip(it.handle);
381
382			if (!IS_ERR_OR_NULL(key))
383				kfree(key);
384
385			if (ret)
386				return ret;
387		}
388
389		/* Skip virtual or partial entries */
390		if (is_virtual || cmode.score < 0 || cmode.id < 0)
391			continue;
392
393		trace_iomfb_color_mode(handle->dcp, cmode.id, cmode.score,
394				       cmode.depth, cmode.colorimetry,
395				       cmode.eotf, cmode.dynamic_range,
396				       cmode.pixel_encoding);
397
398		if (cmode.eotf == DCP_EOTF_SDR_GAMMA) {
399			if (cmode.pixel_encoding == DCP_COLOR_FORMAT_RGB &&
400				cmode.depth <= 10)
401				fill_color_mode(&out->sdr_rgb, &cmode);
402			else if (cmode.pixel_encoding == DCP_COLOR_FORMAT_YCBCR444 &&
403				cmode.depth <= 10)
404				fill_color_mode(&out->sdr_444, &cmode);
405			fill_color_mode(&out->sdr, &cmode);
406		}
407		fill_color_mode(&out->best, &cmode);
408	}
409
410	return 0;
411}
412
413/*
414 * Calculate the pixel clock for a mode given the 16:16 fixed-point refresh
415 * rate. The pixel clock is the refresh rate times the pixel count. DRM
416 * specifies the clock in kHz. The intermediate result may overflow a u32, so
417 * use a u64 where required.
418 */
419static u32 calculate_clock(struct dimension *horiz, struct dimension *vert)
420{
421	u32 pixels = horiz->total * vert->total;
422	u64 clock = mul_u32_u32(pixels, vert->precise_sync_rate);
423
424	return DIV_ROUND_CLOSEST_ULL(clock >> 16, 1000);
425}
426
427static int parse_mode(struct dcp_parse_ctx *handle,
428		      struct dcp_display_mode *out, s64 *score, int width_mm,
429		      int height_mm, unsigned notch_height)
430{
431	int ret = 0;
432	struct iterator it;
433	struct dimension horiz, vert;
434	s64 id = -1;
435	s64 best_color_mode = -1;
436	bool is_virtual = false;
437	struct drm_display_mode *mode = &out->mode;
438
439	dcp_parse_foreach_in_dict(handle, it) {
440		char *key = parse_string(it.handle);
441
442		if (IS_ERR(key))
443			ret = PTR_ERR(key);
444		else if (is_virtual)
445			skip(it.handle);
446		else if (!strcmp(key, "HorizontalAttributes"))
447			ret = parse_dimension(it.handle, &horiz);
448		else if (!strcmp(key, "VerticalAttributes"))
449			ret = parse_dimension(it.handle, &vert);
450		else if (!strcmp(key, "ColorModes"))
451			ret = parse_color_modes(it.handle, out);
452		else if (!strcmp(key, "ID"))
453			ret = parse_int(it.handle, &id);
454		else if (!strcmp(key, "IsVirtual"))
455			ret = parse_bool(it.handle, &is_virtual);
456		else if (!strcmp(key, "Score"))
457			ret = parse_int(it.handle, score);
458		else
459			skip(it.handle);
460
461		if (!IS_ERR_OR_NULL(key))
462			kfree(key);
463
464		if (ret) {
465			trace_iomfb_parse_mode_fail(id, &horiz, &vert, best_color_mode, is_virtual, *score);
466			return ret;
467		}
468	}
469	if (out->sdr_rgb.score >= 0)
470		best_color_mode = out->sdr_rgb.id;
471	else if (out->sdr_444.score >= 0)
472		best_color_mode = out->sdr_444.id;
473	else if (out->sdr.score >= 0)
474		best_color_mode = out->sdr.id;
475	else if (out->best.score >= 0)
476		best_color_mode = out->best.id;
477
478	trace_iomfb_parse_mode_success(id, &horiz, &vert, best_color_mode,
479				       is_virtual, *score);
480
481	/*
482	 * Reject modes without valid color mode.
483	 */
484	if (best_color_mode < 0)
485		return -EINVAL;
486
487	/*
488	 * We need to skip virtual modes. In some cases, virtual modes are "too
489	 * big" for the monitor and can cause breakage. It is unclear why the
490	 * DCP reports these modes at all. Treat as a recoverable error.
491	 */
492	if (is_virtual)
493		return -EINVAL;
494
495	/*
496	 * HACK:
497	 * Ignore the 120 Hz mode on j314/j316 (identified by resolution).
498	 * DCP limits normal swaps to 60 Hz anyway and the 120 Hz mode might
499	 * cause choppiness with X11.
500	 * Just downscoring it and thus making the 60 Hz mode the preferred mode
501	 * seems not enough for some user space.
502	 */
503	if (vert.precise_sync_rate >> 16 == 120 &&
504	    ((horiz.active == 3024 && vert.active == 1964) ||
505	     (horiz.active == 3456 && vert.active == 2234)))
506		return -EINVAL;
507
508	/*
509	 * HACK: reject refresh modes with a pixel clock above 926484,480 kHz
510	 *       (bandwidth limit reported by dcp). This allows 4k 100Hz and
511	 *       5k 60Hz but not much beyond.
512	 *       DSC setup seems to require additional steps
513	 */
514	if (calculate_clock(&horiz, &vert) > 926484) {
515		pr_info("dcp: rejecting mode %lldx%lld@%lld.%03lld (pixel clk:%d)\n",
516			horiz.active, vert.active, vert.precise_sync_rate >> 16,
517			((1000 * vert.precise_sync_rate) >> 16) % 1000,
518			calculate_clock(&horiz, &vert));
519		return -EINVAL;
520	}
521
522	vert.active -= notch_height;
523	vert.sync_width += notch_height;
524
525	/* From here we must succeed. Start filling out the mode. */
526	*mode = (struct drm_display_mode) {
527		.type = DRM_MODE_TYPE_DRIVER,
528		.clock = calculate_clock(&horiz, &vert),
529
530		.vdisplay = vert.active,
531		.vsync_start = vert.active + vert.front_porch,
532		.vsync_end = vert.active + vert.front_porch + vert.sync_width,
533		.vtotal = vert.total,
534
535		.hdisplay = horiz.active,
536		.hsync_start = horiz.active + horiz.front_porch,
537		.hsync_end = horiz.active + horiz.front_porch +
538			     horiz.sync_width,
539		.htotal = horiz.total,
540
541		.width_mm = width_mm,
542		.height_mm = height_mm,
543	};
544
545	drm_mode_set_name(mode);
546
547	out->timing_mode_id = id;
548	out->color_mode_id = best_color_mode;
549
550	trace_iomfb_timing_mode(handle->dcp, id, *score, horiz.active,
551				vert.active, vert.precise_sync_rate,
552				best_color_mode);
553
554	return 0;
555}
556
557struct dcp_display_mode *enumerate_modes(struct dcp_parse_ctx *handle,
558					 unsigned int *count, int width_mm,
559					 int height_mm, unsigned notch_height)
560{
561	struct iterator it;
562	int ret;
563	struct dcp_display_mode *mode, *modes;
564	struct dcp_display_mode *best_mode = NULL;
565	s64 score, best_score = -1;
566
567	ret = iterator_begin(handle, &it, false);
568
569	if (ret)
570		return ERR_PTR(ret);
571
572	/* Start with a worst case allocation */
573	modes = kmalloc_array(it.len, sizeof(*modes), GFP_KERNEL);
574	*count = 0;
575
576	if (!modes)
577		return ERR_PTR(-ENOMEM);
578
579	for (; it.idx < it.len; ++it.idx) {
580		mode = &modes[*count];
581		ret = parse_mode(it.handle, mode, &score, width_mm, height_mm, notch_height);
582
583		/* Errors for a single mode are recoverable -- just skip it. */
584		if (ret)
585			continue;
586
587		/* Process a successful mode */
588		(*count)++;
589
590		if (score > best_score) {
591			best_score = score;
592			best_mode = mode;
593		}
594	}
595
596	if (best_mode != NULL)
597		best_mode->mode.type |= DRM_MODE_TYPE_PREFERRED;
598
599	return modes;
600}
601
602int parse_display_attributes(struct dcp_parse_ctx *handle, int *width_mm,
603			     int *height_mm)
604{
605	int ret = 0;
606	struct iterator it;
607	s64 width_cm = 0, height_cm = 0;
608
609	dcp_parse_foreach_in_dict(handle, it) {
610		char *key = parse_string(it.handle);
611
612		if (IS_ERR(key))
613			ret = PTR_ERR(key);
614		else if (!strcmp(key, "MaxHorizontalImageSize"))
615			ret = parse_int(it.handle, &width_cm);
616		else if (!strcmp(key, "MaxVerticalImageSize"))
617			ret = parse_int(it.handle, &height_cm);
618		else
619			skip(it.handle);
620
621		if (!IS_ERR_OR_NULL(key))
622			kfree(key);
623
624		if (ret)
625			return ret;
626	}
627
628	/* 1cm = 10mm */
629	*width_mm = 10 * width_cm;
630	*height_mm = 10 * height_cm;
631
632	return 0;
633}
634
635int parse_epic_service_init(struct dcp_parse_ctx *handle, const char **name,
636			    const char **class, s64 *unit)
637{
638	int ret = 0;
639	struct iterator it;
640	bool parsed_unit = false;
641	bool parsed_name = false;
642	bool parsed_class = false;
643
644	*name = ERR_PTR(-ENOENT);
645	*class = ERR_PTR(-ENOENT);
646
647	dcp_parse_foreach_in_dict(handle, it) {
648		char *key = parse_string(it.handle);
649
650		if (IS_ERR(key)) {
651			ret = PTR_ERR(key);
652			break;
653		}
654
655		if (!strcmp(key, "EPICName")) {
656			*name = parse_string(it.handle);
657			if (IS_ERR(*name))
658				ret = PTR_ERR(*name);
659			else
660				parsed_name = true;
661		} else if (!strcmp(key, "EPICProviderClass")) {
662			*class = parse_string(it.handle);
663			if (IS_ERR(*class))
664				ret = PTR_ERR(*class);
665			else
666				parsed_class = true;
667		} else if (!strcmp(key, "EPICUnit")) {
668			ret = parse_int(it.handle, unit);
669			if (!ret)
670				parsed_unit = true;
671		} else {
672			skip(it.handle);
673		}
674
675		kfree(key);
676		if (ret)
677			break;
678	}
679
680	if (!parsed_unit || !parsed_name || !parsed_class)
681		ret = -ENOENT;
682
683	if (ret) {
684		if (!IS_ERR(*name)) {
685			kfree(*name);
686			*name = ERR_PTR(ret);
687		}
688		if (!IS_ERR(*class)) {
689			kfree(*class);
690			*class = ERR_PTR(ret);
691		}
692	}
693
694	return ret;
695}
696
697static int parse_sample_rate_bit(struct dcp_parse_ctx *handle, unsigned int *ratebit)
698{
699	s64 rate;
700	int ret = parse_int(handle, &rate);
701
702	if (ret)
703		return ret;
704
705	*ratebit = snd_pcm_rate_to_rate_bit(rate);
706	if (*ratebit == SNDRV_PCM_RATE_KNOT) {
707		/*
708		 * The rate wasn't recognized, and unless we supply
709		 * a supplementary constraint, the SNDRV_PCM_RATE_KNOT bit
710		 * will allow any rate. So clear it.
711		 */
712		*ratebit = 0;
713	}
714
715	return 0;
716}
717
718static int parse_sample_fmtbit(struct dcp_parse_ctx *handle, u64 *fmtbit)
719{
720	s64 sample_size;
721	int ret = parse_int(handle, &sample_size);
722
723	if (ret)
724		return ret;
725
726	switch (sample_size) {
727	case 16:
728		*fmtbit = SNDRV_PCM_FMTBIT_S16;
729		break;
730	case 20:
731		*fmtbit = SNDRV_PCM_FMTBIT_S20;
732		break;
733	case 24:
734		*fmtbit = SNDRV_PCM_FMTBIT_S24;
735		break;
736	case 32:
737		*fmtbit = SNDRV_PCM_FMTBIT_S32;
738		break;
739	default:
740		*fmtbit = 0;
741		break;
742	}
743
744	return 0;
745}
746
747static struct {
748	const char *label;
749	u8 type;
750} chan_position_names[] = {
751	{ "Front Left", SNDRV_CHMAP_FL },
752	{ "Front Right", SNDRV_CHMAP_FR },
753	{ "Rear Left", SNDRV_CHMAP_RL },
754	{ "Rear Right", SNDRV_CHMAP_RR },
755	{ "Front Center", SNDRV_CHMAP_FC },
756	{ "Low Frequency Effects", SNDRV_CHMAP_LFE },
757	{ "Rear Center", SNDRV_CHMAP_RC },
758	{ "Front Left Center", SNDRV_CHMAP_FLC },
759	{ "Front Right Center", SNDRV_CHMAP_FRC },
760	{ "Rear Left Center", SNDRV_CHMAP_RLC },
761	{ "Rear Right Center", SNDRV_CHMAP_RRC },
762	{ "Front Left Wide", SNDRV_CHMAP_FLW },
763	{ "Front Right Wide", SNDRV_CHMAP_FRW },
764	{ "Front Left High", SNDRV_CHMAP_FLH },
765	{ "Front Center High", SNDRV_CHMAP_FCH },
766	{ "Front Right High", SNDRV_CHMAP_FRH },
767	{ "Top Center", SNDRV_CHMAP_TC },
768};
769
770static void append_chmap(struct snd_pcm_chmap_elem *chmap, u8 type)
771{
772	if (!chmap || chmap->channels >= ARRAY_SIZE(chmap->map))
773		return;
774
775	chmap->map[chmap->channels] = type;
776	chmap->channels++;
777}
778
779static int parse_chmap(struct dcp_parse_ctx *handle, struct snd_pcm_chmap_elem *chmap)
780{
781	struct iterator it;
782	int i, ret;
783
784	if (!chmap) {
785		skip(handle);
786		return 0;
787	}
788
789	chmap->channels = 0;
790
791	dcp_parse_foreach_in_array(handle, it) {
792		for (i = 0; i < ARRAY_SIZE(chan_position_names); i++)
793			if (consume_string(it.handle, chan_position_names[i].label))
794				break;
795
796		if (i == ARRAY_SIZE(chan_position_names)) {
797			ret = skip(it.handle);
798			if (ret)
799				return ret;
800
801			append_chmap(chmap, SNDRV_CHMAP_UNKNOWN);
802			continue;
803		}
804
805		append_chmap(chmap, chan_position_names[i].type);
806	}
807
808	return 0;
809}
810
811static int parse_chan_layout_element(struct dcp_parse_ctx *handle,
812				     unsigned int *nchans_out,
813				     struct snd_pcm_chmap_elem *chmap)
814{
815	struct iterator it;
816	int ret;
817	s64 nchans = 0;
818
819	dcp_parse_foreach_in_dict(handle, it) {
820		if (consume_string(it.handle, "ActiveChannelCount"))
821			ret = parse_int(it.handle, &nchans);
822		else if (consume_string(it.handle, "ChannelLayout"))
823			ret = parse_chmap(it.handle, chmap);
824		else
825			ret = skip_pair(it.handle);
826
827		if (ret)
828			return ret;
829	}
830
831	if (nchans_out)
832		*nchans_out = nchans;
833
834	return 0;
835}
836
837static int parse_nchans_mask(struct dcp_parse_ctx *handle, unsigned int *mask)
838{
839	struct iterator it;
840	int ret;
841
842	*mask = 0;
843
844	dcp_parse_foreach_in_array(handle, it) {
845		int nchans;
846
847		ret = parse_chan_layout_element(it.handle, &nchans, NULL);
848		if (ret)
849			return ret;
850		*mask |= 1 << nchans;
851	}
852
853	return 0;
854}
855
856static int parse_avep_element(struct dcp_parse_ctx *handle,
857			      struct dcp_sound_format_mask *sieve,
858			      struct dcp_sound_format_mask *hits)
859{
860	struct dcp_sound_format_mask mask = {0, 0, 0};
861	struct iterator it;
862	int ret;
863
864	dcp_parse_foreach_in_dict(handle, it) {
865		if (consume_string(handle, "StreamSampleRate"))
866			ret = parse_sample_rate_bit(it.handle, &mask.rates);
867		else if (consume_string(handle, "SampleSize"))
868			ret = parse_sample_fmtbit(it.handle, &mask.formats);
869		else if (consume_string(handle, "AudioChannelLayoutElements"))
870			ret = parse_nchans_mask(it.handle, &mask.nchans);
871		else
872			ret = skip_pair(it.handle);
873
874		if (ret)
875			return ret;
876	}
877
878	trace_avep_sound_mode(handle->dcp, mask.rates, mask.formats, mask.nchans);
879
880	if (!(mask.rates & sieve->rates) || !(mask.formats & sieve->formats) ||
881		!(mask.nchans & sieve->nchans))
882	    return 0;
883
884	if (hits) {
885		hits->rates |= mask.rates;
886		hits->formats |= mask.formats;
887		hits->nchans |= mask.nchans;
888	}
889
890	return 1;
891}
892
893static int parse_mode_in_avep_element(struct dcp_parse_ctx *handle,
894				      unsigned int selected_nchans,
895				      struct snd_pcm_chmap_elem *chmap,
896				      struct dcp_sound_cookie *cookie)
897{
898	struct iterator it;
899	struct dcp_parse_ctx save_handle;
900	int ret;
901
902	dcp_parse_foreach_in_dict(handle, it) {
903		if (consume_string(it.handle, "AudioChannelLayoutElements")) {
904			struct iterator inner_it;
905			int nchans;
906
907			dcp_parse_foreach_in_array(it.handle, inner_it) {
908				save_handle = *it.handle;
909				ret = parse_chan_layout_element(inner_it.handle,
910								&nchans, NULL);
911				if (ret)
912					return ret;
913
914				if (nchans != selected_nchans)
915					continue;
916
917				/*
918				 * Now that we know this layout matches the
919				 * selected channel number, reread the element
920				 * and fill in the channel map.
921				 */
922				*inner_it.handle = save_handle;
923				ret = parse_chan_layout_element(inner_it.handle,
924								NULL, chmap);
925				if (ret)
926					return ret;
927			}
928		} else if (consume_string(it.handle, "ElementData")) {
929			const u8 *blob;
930
931			ret = parse_blob(it.handle, sizeof(*cookie), &blob);
932			if (ret)
933				return ret;
934
935			if (cookie)
936				memcpy(cookie, blob, sizeof(*cookie));
937		} else {
938			ret = skip_pair(it.handle);
939			if (ret)
940				return ret;
941		}
942	}
943
944	return 0;
945}
946
947int parse_sound_constraints(struct dcp_parse_ctx *handle,
948			    struct dcp_sound_format_mask *sieve,
949			    struct dcp_sound_format_mask *hits)
950{
951	int ret;
952	struct iterator it;
953
954	if (hits) {
955		hits->rates = 0;
956		hits->formats = 0;
957		hits->nchans = 0;
958	}
959
960	dcp_parse_foreach_in_array(handle, it) {
961		ret = parse_avep_element(it.handle, sieve, hits);
962
963		if (ret < 0)
964			return ret;
965	}
966
967	return 0;
968}
969EXPORT_SYMBOL_GPL(parse_sound_constraints);
970
971int parse_sound_mode(struct dcp_parse_ctx *handle,
972		     struct dcp_sound_format_mask *sieve,
973		     struct snd_pcm_chmap_elem *chmap,
974		     struct dcp_sound_cookie *cookie)
975{
976	struct dcp_parse_ctx save_handle;
977	struct iterator it;
978	int ret;
979
980	dcp_parse_foreach_in_array(handle, it) {
981		save_handle = *it.handle;
982		ret = parse_avep_element(it.handle, sieve, NULL);
983
984		if (!ret)
985			continue;
986
987		if (ret < 0)
988			return ret;
989
990		ret = parse_mode_in_avep_element(&save_handle, __ffs(sieve->nchans),
991						 chmap, cookie);
992		if (ret < 0)
993			return ret;
994		return 1;
995	}
996
997	return 0;
998}
999EXPORT_SYMBOL_GPL(parse_sound_mode);
1000
1001int parse_system_log_mnits(struct dcp_parse_ctx *handle, struct dcp_system_ev_mnits *entry)
1002{
1003	struct iterator it;
1004	int ret;
1005	s64 mnits = -1;
1006	s64 idac = -1;
1007	s64 timestamp = -1;
1008	bool type_match = false;
1009
1010	dcp_parse_foreach_in_dict(handle, it) {
1011		char *key = parse_string(it.handle);
1012		if (IS_ERR(key)) {
1013			ret = PTR_ERR(key);
1014		} else if (!strcmp(key, "mNits")) {
1015			ret = parse_int(it.handle, &mnits);
1016		} else if (!strcmp(key, "iDAC")) {
1017			ret = parse_int(it.handle, &idac);
1018		} else if (!strcmp(key, "logEvent")) {
1019			const char * value = parse_string(it.handle);
1020			if (!IS_ERR_OR_NULL(value)) {
1021				type_match = strcmp(value, "Display (Event Forward)") == 0;
1022				kfree(value);
1023			}
1024		} else if (!strcmp(key, "timestamp")) {
1025			ret = parse_int(it.handle, &timestamp);
1026		} else {
1027			skip(it.handle);
1028		}
1029
1030		if (!IS_ERR_OR_NULL(key))
1031			kfree(key);
1032
1033		if (ret) {
1034			pr_err("dcp parser: failed to parse mNits sys event\n");
1035			return ret;
1036		}
1037	}
1038
1039	if (!type_match ||  mnits < 0 || idac < 0 || timestamp < 0)
1040		return -EINVAL;
1041
1042	entry->millinits = mnits;
1043	entry->idac = idac;
1044	entry->timestamp = timestamp;
1045
1046	return 0;
1047}
1048