Skip to content

Commit 2d782b0

Browse files
povikmarcan
authored andcommitted
gpu: drm: apple: Add sound mode parsing
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
1 parent 3fd3f45 commit 2d782b0

4 files changed

Lines changed: 351 additions & 0 deletions

File tree

drivers/gpu/drm/apple/dcp-internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,4 +195,6 @@ struct apple_dcp {
195195
int dcp_backlight_register(struct apple_dcp *dcp);
196196
bool dcp_has_panel(struct apple_dcp *dcp);
197197

198+
#define DCP_AUDIO_MAX_CHANS 15
199+
198200
#endif /* __APPLE_DCP_INTERNAL_H__ */

drivers/gpu/drm/apple/parser.c

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <linux/string.h>
88
#include <linux/slab.h>
99

10+
#include <sound/pcm.h> // for sound format masks
11+
1012
#include "parser.h"
1113
#include "trace.h"
1214

@@ -586,3 +588,307 @@ int parse_display_attributes(struct dcp_parse_ctx *handle, int *width_mm,
586588

587589
return 0;
588590
}
591+
592+
int parse_sample_rate_bit(struct dcp_parse_ctx *handle, unsigned int *ratebit)
593+
{
594+
s64 rate;
595+
int ret = parse_int(handle, &rate);
596+
597+
if (ret)
598+
return ret;
599+
600+
*ratebit = snd_pcm_rate_to_rate_bit(rate);
601+
if (*ratebit == SNDRV_PCM_RATE_KNOT) {
602+
/*
603+
* The rate wasn't recognized, and unless we supply
604+
* a supplementary constraint, the SNDRV_PCM_RATE_KNOT bit
605+
* will allow any rate. So clear it.
606+
*/
607+
*ratebit = 0;
608+
}
609+
610+
return 0;
611+
}
612+
613+
int parse_sample_fmtbit(struct dcp_parse_ctx *handle, u64 *fmtbit)
614+
{
615+
s64 sample_size;
616+
int ret = parse_int(handle, &sample_size);
617+
618+
if (ret)
619+
return ret;
620+
621+
switch (sample_size) {
622+
case 16:
623+
*fmtbit = SNDRV_PCM_FMTBIT_S16;
624+
break;
625+
case 20:
626+
*fmtbit = SNDRV_PCM_FMTBIT_S20;
627+
break;
628+
case 24:
629+
*fmtbit = SNDRV_PCM_FMTBIT_S24;
630+
break;
631+
case 32:
632+
*fmtbit = SNDRV_PCM_FMTBIT_S32;
633+
break;
634+
default:
635+
*fmtbit = 0;
636+
break;
637+
}
638+
639+
return 0;
640+
}
641+
642+
static struct {
643+
const char *label;
644+
u8 type;
645+
} chan_position_names[] = {
646+
{ "Front Left", SNDRV_CHMAP_FL },
647+
{ "Front Right", SNDRV_CHMAP_FR },
648+
{ "Rear Left", SNDRV_CHMAP_RL },
649+
{ "Rear Right", SNDRV_CHMAP_RR },
650+
{ "Front Center", SNDRV_CHMAP_FC },
651+
{ "Low Frequency Effects", SNDRV_CHMAP_LFE },
652+
{ "Rear Center", SNDRV_CHMAP_RC },
653+
{ "Front Left Center", SNDRV_CHMAP_FLC },
654+
{ "Front Right Center", SNDRV_CHMAP_FRC },
655+
{ "Rear Left Center", SNDRV_CHMAP_RLC },
656+
{ "Rear Right Center", SNDRV_CHMAP_RRC },
657+
{ "Front Left Wide", SNDRV_CHMAP_FLW },
658+
{ "Front Right Wide", SNDRV_CHMAP_FRW },
659+
{ "Front Left High", SNDRV_CHMAP_FLH },
660+
{ "Front Center High", SNDRV_CHMAP_FCH },
661+
{ "Front Right High", SNDRV_CHMAP_FRH },
662+
{ "Top Center", SNDRV_CHMAP_TC },
663+
};
664+
665+
static void append_chmap(struct snd_pcm_chmap_elem *chmap, u8 type)
666+
{
667+
if (!chmap || chmap->channels >= ARRAY_SIZE(chmap->map))
668+
return;
669+
670+
chmap->map[chmap->channels] = type;
671+
chmap->channels++;
672+
}
673+
674+
static int parse_chmap(struct dcp_parse_ctx *handle, struct snd_pcm_chmap_elem *chmap)
675+
{
676+
struct iterator it;
677+
int i, ret;
678+
679+
if (!chmap) {
680+
skip(handle);
681+
return 0;
682+
}
683+
684+
chmap->channels = 0;
685+
686+
dcp_parse_foreach_in_array(handle, it) {
687+
for (i = 0; i < ARRAY_SIZE(chan_position_names); i++)
688+
if (consume_string(it.handle, chan_position_names[i].label))
689+
break;
690+
691+
if (i == ARRAY_SIZE(chan_position_names)) {
692+
ret = skip(it.handle);
693+
if (ret)
694+
return ret;
695+
696+
append_chmap(chmap, SNDRV_CHMAP_UNKNOWN);
697+
continue;
698+
}
699+
700+
append_chmap(chmap, chan_position_names[i].type);
701+
}
702+
703+
return 0;
704+
}
705+
706+
static int parse_chan_layout_element(struct dcp_parse_ctx *handle,
707+
unsigned int *nchans_out,
708+
struct snd_pcm_chmap_elem *chmap)
709+
{
710+
struct iterator it;
711+
int ret;
712+
s64 nchans = 0;
713+
714+
dcp_parse_foreach_in_dict(handle, it) {
715+
if (consume_string(it.handle, "ActiveChannelCount"))
716+
ret = parse_int(it.handle, &nchans);
717+
else if (consume_string(it.handle, "ChannelLayout"))
718+
ret = parse_chmap(it.handle, chmap);
719+
else
720+
ret = skip_pair(it.handle);
721+
722+
if (ret)
723+
return ret;
724+
}
725+
726+
if (nchans_out)
727+
*nchans_out = nchans;
728+
729+
return 0;
730+
}
731+
732+
static int parse_nchans_mask(struct dcp_parse_ctx *handle, unsigned int *mask)
733+
{
734+
struct iterator it;
735+
int ret;
736+
737+
*mask = 0;
738+
739+
dcp_parse_foreach_in_array(handle, it) {
740+
int nchans;
741+
742+
ret = parse_chan_layout_element(it.handle, &nchans, NULL);
743+
if (ret)
744+
return ret;
745+
*mask |= 1 << nchans;
746+
}
747+
748+
return 0;
749+
}
750+
751+
static int parse_avep_element(struct dcp_parse_ctx *handle,
752+
struct dcp_sound_format_mask *sieve,
753+
struct dcp_sound_format_mask *hits)
754+
{
755+
struct dcp_sound_format_mask mask = {0, 0, 0};
756+
struct iterator it;
757+
int ret;
758+
759+
dcp_parse_foreach_in_dict(handle, it) {
760+
if (consume_string(handle, "StreamSampleRate"))
761+
ret = parse_sample_rate_bit(it.handle, &mask.rates);
762+
else if (consume_string(handle, "SampleSize"))
763+
ret = parse_sample_fmtbit(it.handle, &mask.formats);
764+
else if (consume_string(handle, "AudioChannelLayoutElements"))
765+
ret = parse_nchans_mask(it.handle, &mask.nchans);
766+
else
767+
ret = skip_pair(it.handle);
768+
769+
if (ret)
770+
return ret;
771+
}
772+
773+
trace_avep_sound_mode(handle->dcp, mask.rates, mask.formats, mask.nchans);
774+
775+
if (!(mask.rates & sieve->rates) || !(mask.formats & sieve->formats) ||
776+
!(mask.nchans & sieve->nchans))
777+
return 0;
778+
779+
if (hits) {
780+
hits->rates |= mask.rates;
781+
hits->formats |= mask.formats;
782+
hits->nchans |= mask.nchans;
783+
}
784+
785+
return 1;
786+
}
787+
788+
static int parse_mode_in_avep_element(struct dcp_parse_ctx *handle,
789+
unsigned int selected_nchans,
790+
struct snd_pcm_chmap_elem *chmap,
791+
struct dcp_sound_cookie *cookie)
792+
{
793+
struct iterator it;
794+
struct dcp_parse_ctx save_handle;
795+
int ret;
796+
797+
dcp_parse_foreach_in_dict(handle, it) {
798+
if (consume_string(it.handle, "AudioChannelLayoutElements")) {
799+
struct iterator inner_it;
800+
int nchans;
801+
802+
dcp_parse_foreach_in_array(it.handle, inner_it) {
803+
save_handle = *it.handle;
804+
ret = parse_chan_layout_element(inner_it.handle,
805+
&nchans, NULL);
806+
if (ret)
807+
return ret;
808+
809+
if (nchans != selected_nchans)
810+
continue;
811+
812+
/*
813+
* Now that we know this layout matches the
814+
* selected channel number, reread the element
815+
* and fill in the channel map.
816+
*/
817+
*inner_it.handle = save_handle;
818+
ret = parse_chan_layout_element(inner_it.handle,
819+
NULL, chmap);
820+
if (ret)
821+
return ret;
822+
}
823+
} else if (consume_string(it.handle, "ElementData")) {
824+
u8 *blob;
825+
826+
ret = parse_blob(it.handle, sizeof(*cookie), &blob);
827+
if (ret)
828+
return ret;
829+
830+
if (cookie)
831+
memcpy(cookie, blob, sizeof(*cookie));
832+
} else {
833+
ret = skip_pair(it.handle);
834+
if (ret)
835+
return ret;
836+
}
837+
}
838+
839+
return 0;
840+
}
841+
842+
int parse_sound_constraints(struct dcp_parse_ctx *handle,
843+
struct dcp_sound_format_mask *sieve,
844+
struct dcp_sound_format_mask *hits)
845+
{
846+
int ret;
847+
struct iterator it;
848+
849+
if (hits) {
850+
hits->rates = 0;
851+
hits->formats = 0;
852+
hits->nchans = 0;
853+
}
854+
855+
dcp_parse_foreach_in_array(handle, it) {
856+
ret = parse_avep_element(it.handle, sieve, hits);
857+
858+
if (ret < 0)
859+
return ret;
860+
}
861+
862+
return 0;
863+
}
864+
EXPORT_SYMBOL_GPL(parse_sound_constraints);
865+
866+
int parse_sound_mode(struct dcp_parse_ctx *handle,
867+
struct dcp_sound_format_mask *sieve,
868+
struct snd_pcm_chmap_elem *chmap,
869+
struct dcp_sound_cookie *cookie)
870+
{
871+
struct dcp_parse_ctx save_handle;
872+
struct iterator it;
873+
int ret;
874+
875+
dcp_parse_foreach_in_array(handle, it) {
876+
save_handle = *it.handle;
877+
ret = parse_avep_element(it.handle, sieve, NULL);
878+
879+
if (!ret)
880+
continue;
881+
882+
if (ret < 0)
883+
return ret;
884+
885+
ret = parse_mode_in_avep_element(&save_handle, __ffs(sieve->nchans),
886+
chmap, cookie);
887+
if (ret < 0)
888+
return ret;
889+
return 1;
890+
}
891+
892+
return 0;
893+
}
894+
EXPORT_SYMBOL_GPL(parse_sound_mode);

drivers/gpu/drm/apple/parser.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,24 @@ struct dcp_display_mode *enumerate_modes(struct dcp_parse_ctx *handle,
3232
int parse_display_attributes(struct dcp_parse_ctx *handle, int *width_mm,
3333
int *height_mm);
3434

35+
36+
struct dcp_sound_format_mask {
37+
u64 formats; /* SNDRV_PCM_FMTBIT_* */
38+
unsigned int rates; /* SNDRV_PCM_RATE_* */
39+
unsigned int nchans;
40+
};
41+
42+
struct dcp_sound_cookie {
43+
u8 data[24];
44+
};
45+
46+
struct snd_pcm_chmap_elem;
47+
int parse_sound_constraints(struct dcp_parse_ctx *handle,
48+
struct dcp_sound_format_mask *sieve,
49+
struct dcp_sound_format_mask *hits);
50+
int parse_sound_mode(struct dcp_parse_ctx *handle,
51+
struct dcp_sound_format_mask *sieve,
52+
struct snd_pcm_chmap_elem *chmap,
53+
struct dcp_sound_cookie *cookie);
54+
3555
#endif

drivers/gpu/drm/apple/trace.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,29 @@ TRACE_EVENT(iomfb_timing_mode,
291291
)
292292
);
293293

294+
TRACE_EVENT(avep_sound_mode,
295+
TP_PROTO(struct apple_dcp *dcp, u32 rates, u64 formats, unsigned int nchans),
296+
TP_ARGS(dcp, rates, formats, nchans),
297+
TP_STRUCT__entry(
298+
__field(u64, dcp)
299+
__field(u32, rates)
300+
__field(u64, formats)
301+
__field(unsigned int, nchans)
302+
),
303+
TP_fast_assign(
304+
__entry->dcp = (u64)dcp;
305+
__entry->rates = rates;
306+
__entry->formats = formats;
307+
__entry->nchans = nchans;
308+
),
309+
TP_printk("dcp=%llx, rates=%#x, formats=%#llx, nchans=%#x",
310+
__entry->dcp,
311+
__entry->rates,
312+
__entry->formats,
313+
__entry->nchans
314+
)
315+
);
316+
294317
#endif /* _TRACE_DCP_H */
295318

296319
/* This part must be outside protection */

0 commit comments

Comments
 (0)