@@ -666,6 +666,7 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data,
666666 struct copier_data * cd = module_get_private_data (mod );
667667 struct list_item * sink_list ;
668668 struct comp_buffer * sink ;
669+ uint32_t chmap ;
669670
670671 if (max_data_size < sizeof (* sink_fmt )) {
671672 comp_err (dev , "error: max_data_size %d should be bigger than %d" , max_data_size ,
@@ -691,9 +692,15 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data,
691692 }
692693
693694 cd -> out_fmt [sink_fmt -> sink_id ] = sink_fmt -> sink_fmt ;
695+
696+ if (cd -> endpoint_num > 0 && dev -> ipc_config .type == SOF_COMP_DAI )
697+ chmap = cd -> dd [0 ]-> chmap ;
698+ else
699+ chmap = DUMMY_CHMAP ;
700+
694701 cd -> converter [sink_fmt -> sink_id ] = get_converter_func (& sink_fmt -> source_fmt ,
695702 & sink_fmt -> sink_fmt , ipc4_gtw_none ,
696- ipc4_bidirection , DUMMY_CHMAP );
703+ ipc4_bidirection , chmap );
697704
698705 /* update corresponding sink format */
699706 list_for_item (sink_list , & dev -> bsink_list ) {
@@ -746,6 +753,82 @@ static int set_attenuation(struct comp_dev *dev, uint32_t data_offset, const cha
746753 return 0 ;
747754}
748755
756+ static int set_chmap (struct comp_dev * dev , const void * data , size_t data_size )
757+ {
758+ const struct ipc4_copier_config_channel_map * chmap_cfg = data ;
759+ struct processing_module * mod = comp_mod (dev );
760+ struct copier_data * cd = module_get_private_data (mod );
761+ enum ipc4_direction_type dir ;
762+ struct ipc4_audio_format in_fmt = cd -> config .base .audio_fmt ;
763+ struct ipc4_audio_format out_fmt = cd -> config .out_fmt ;
764+ pcm_converter_func process ;
765+ pcm_converter_func converters [IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT ];
766+ int i ;
767+ uint32_t irq_flags ;
768+
769+ if (data_size < sizeof (* chmap_cfg )) {
770+ comp_err (dev , "Wrong payload size: %d" , data_size );
771+ return - EINVAL ;
772+ }
773+
774+ if (cd -> endpoint_num == 0 || dev -> ipc_config .type != SOF_COMP_DAI ) {
775+ comp_err (dev , "Only DAI gateway supports changing chmap" );
776+ return - EINVAL ;
777+ }
778+
779+ comp_info (dev , "New chmap requested: %x" , chmap_cfg -> channel_map );
780+
781+ if (!cd -> dd [0 ]-> dma_buffer ) {
782+ /* DMA buffer not yet created. Remember the chmap, it will be used
783+ * later in .params() handler.
784+ *
785+ * The assignment should be atomic as LL thread can preempt this IPC thread.
786+ */
787+ cd -> dd [0 ]-> chmap = chmap_cfg -> channel_map ;
788+ return 0 ;
789+ }
790+
791+ copier_dai_adjust_params (cd , & in_fmt , & out_fmt );
792+
793+ dir = (cd -> direction == SOF_IPC_STREAM_PLAYBACK ) ?
794+ ipc4_playback : ipc4_capture ;
795+
796+ process = get_converter_func (& in_fmt , & out_fmt , cd -> gtw_type , dir , chmap_cfg -> channel_map );
797+
798+ if (!process ) {
799+ comp_err (dev , "No gtw converter func found!" );
800+ return - EINVAL ;
801+ }
802+
803+ /* Channel map is same for all sinks. However, as sinks allowed to have different
804+ * sample formats, get new convert/remap function for each sink.
805+ */
806+ for (i = 0 ; i < IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT ; i ++ ) {
807+ if (cd -> converter [i ]) {
808+ converters [i ] = get_converter_func (& in_fmt , & cd -> out_fmt [i ],
809+ ipc4_gtw_none , ipc4_bidirection ,
810+ chmap_cfg -> channel_map );
811+ /* Do not report an error if converter not found as sinks could be
812+ * bound/unbound on a fly and out_fmt[i] may contain obsolete data.
813+ */
814+ } else {
815+ converters [i ] = NULL ;
816+ }
817+ }
818+
819+ /* Atomically update chmap, process and converters */
820+ irq_local_disable (irq_flags );
821+
822+ cd -> dd [0 ]-> chmap = chmap_cfg -> channel_map ;
823+ cd -> dd [0 ]-> process = process ;
824+ for (i = 0 ; i < IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT ; i ++ )
825+ cd -> converter [i ] = converters [i ];
826+
827+ irq_local_enable (irq_flags );
828+
829+ return 0 ;
830+ }
831+
749832static int copier_set_configuration (struct processing_module * mod ,
750833 uint32_t config_id ,
751834 enum module_cfg_fragment_position pos ,
@@ -763,6 +846,8 @@ static int copier_set_configuration(struct processing_module *mod,
763846 return copier_set_sink_fmt (dev , fragment , fragment_size );
764847 case IPC4_COPIER_MODULE_CFG_ATTENUATION :
765848 return set_attenuation (dev , fragment_size , (const char * )fragment );
849+ case IPC4_COPIER_MODULE_CFG_PARAM_CHANNEL_MAP :
850+ return set_chmap (dev , fragment , fragment_size );
766851 default :
767852 return - EINVAL ;
768853 }
0 commit comments