@@ -661,6 +661,7 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data,
661661 const struct ipc4_copier_config_set_sink_format * sink_fmt = data ;
662662 struct processing_module * mod = comp_mod (dev );
663663 struct copier_data * cd = module_get_private_data (mod );
664+ uint32_t chmap ;
664665
665666 if (max_data_size < sizeof (* sink_fmt )) {
666667 comp_err (dev , "error: max_data_size %d should be bigger than %d" , max_data_size ,
@@ -686,9 +687,15 @@ static int copier_set_sink_fmt(struct comp_dev *dev, const void *data,
686687 }
687688
688689 cd -> out_fmt [sink_fmt -> sink_id ] = sink_fmt -> sink_fmt ;
690+
691+ if (cd -> endpoint_num > 0 && dev -> ipc_config .type == SOF_COMP_DAI )
692+ chmap = cd -> dd [0 ]-> chmap ;
693+ else
694+ chmap = DUMMY_CHMAP ;
695+
689696 cd -> converter [sink_fmt -> sink_id ] = get_converter_func (& sink_fmt -> source_fmt ,
690697 & sink_fmt -> sink_fmt , ipc4_gtw_none ,
691- ipc4_bidirection , DUMMY_CHMAP );
698+ ipc4_bidirection , chmap );
692699
693700 return 0 ;
694701}
@@ -728,6 +735,82 @@ static int set_attenuation(struct comp_dev *dev, uint32_t data_offset, const cha
728735 return 0 ;
729736}
730737
738+ static int set_chmap (struct comp_dev * dev , const void * data , size_t data_size )
739+ {
740+ const struct ipc4_copier_config_channel_map * chmap_cfg = data ;
741+ struct processing_module * mod = comp_mod (dev );
742+ struct copier_data * cd = module_get_private_data (mod );
743+ enum ipc4_direction_type dir ;
744+ struct ipc4_audio_format in_fmt = cd -> config .base .audio_fmt ;
745+ struct ipc4_audio_format out_fmt = cd -> config .out_fmt ;
746+ pcm_converter_func process ;
747+ pcm_converter_func converters [IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT ];
748+ int i ;
749+ uint32_t irq_flags ;
750+
751+ if (data_size < sizeof (* chmap_cfg )) {
752+ comp_err (dev , "Wrong payload size: %d" , data_size );
753+ return - EINVAL ;
754+ }
755+
756+ if (cd -> endpoint_num == 0 || dev -> ipc_config .type != SOF_COMP_DAI ) {
757+ comp_err (dev , "Only DAI gateway supports changing chmap" );
758+ return - EINVAL ;
759+ }
760+
761+ comp_info (dev , "New chmap requested: %x" , chmap_cfg -> channel_map );
762+
763+ if (!cd -> dd [0 ]-> dma_buffer ) {
764+ /* DMA buffer not yet created. Remember the chmap, it will be used
765+ * later in .params() handler.
766+ *
767+ * The assignment should be atomic as LL thread can preempt this IPC thread.
768+ */
769+ cd -> dd [0 ]-> chmap = chmap_cfg -> channel_map ;
770+ return 0 ;
771+ }
772+
773+ copier_dai_adjust_params (cd , & in_fmt , & out_fmt );
774+
775+ dir = (cd -> direction == SOF_IPC_STREAM_PLAYBACK ) ?
776+ ipc4_playback : ipc4_capture ;
777+
778+ process = get_converter_func (& in_fmt , & out_fmt , cd -> gtw_type , dir , chmap_cfg -> channel_map );
779+
780+ if (!process ) {
781+ comp_err (dev , "No gtw converter func found!" );
782+ return - EINVAL ;
783+ }
784+
785+ /* Channel map is same for all sinks. However, as sinks allowed to have different
786+ * sample formats, get new convert/remap function for each sink.
787+ */
788+ for (i = 0 ; i < IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT ; i ++ ) {
789+ if (cd -> converter [i ]) {
790+ converters [i ] = get_converter_func (& in_fmt , & cd -> out_fmt [i ],
791+ ipc4_gtw_none , ipc4_bidirection ,
792+ chmap_cfg -> channel_map );
793+ /* Do not report an error if converter not found as sinks could be
794+ * bound/unbound on a fly and out_fmt[i] may contain obsolete data.
795+ */
796+ } else {
797+ converters [i ] = NULL ;
798+ }
799+ }
800+
801+ /* Atomically update chmap, process and converters */
802+ irq_local_disable (irq_flags );
803+
804+ cd -> dd [0 ]-> chmap = chmap_cfg -> channel_map ;
805+ cd -> dd [0 ]-> process = process ;
806+ for (i = 0 ; i < IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT ; i ++ )
807+ cd -> converter [i ] = converters [i ];
808+
809+ irq_local_enable (irq_flags );
810+
811+ return 0 ;
812+ }
813+
731814static int copier_set_configuration (struct processing_module * mod ,
732815 uint32_t config_id ,
733816 enum module_cfg_fragment_position pos ,
@@ -745,6 +828,8 @@ static int copier_set_configuration(struct processing_module *mod,
745828 return copier_set_sink_fmt (dev , fragment , fragment_size );
746829 case IPC4_COPIER_MODULE_CFG_ATTENUATION :
747830 return set_attenuation (dev , fragment_size , (const char * )fragment );
831+ case IPC4_COPIER_MODULE_CFG_PARAM_CHANNEL_MAP :
832+ return set_chmap (dev , fragment , fragment_size );
748833 default :
749834 return - EINVAL ;
750835 }
0 commit comments