5050/* IIR component private data */
5151struct comp_data {
5252 struct iir_state_df2t iir [PLATFORM_MAX_CHANNELS ]; /**< filters state */
53- struct sof_eq_iir_config * config ; /**< pointer to setup blob */
54- enum sof_ipc_frame source_format ; /**< source frame format */
55- enum sof_ipc_frame sink_format ; /**< sink frame format */
56- int64_t * iir_delay ; /**< pointer to allocated RAM */
57- size_t iir_delay_size ; /**< allocated size */
53+ struct sof_eq_iir_config * config ; /**< pointer to setup blob */
54+ struct sof_eq_iir_config * config_new ; /**< pointer to new setup */
55+ enum sof_ipc_frame source_format ; /**< source frame format */
56+ enum sof_ipc_frame sink_format ; /**< sink frame format */
57+ int64_t * iir_delay ; /**< pointer to allocated RAM */
58+ size_t iir_delay_size ; /**< allocated size */
5859 void (* eq_iir_func )(struct comp_dev * dev ,
5960 struct comp_buffer * source ,
6061 struct comp_buffer * sink ,
@@ -383,38 +384,32 @@ static void eq_iir_free_delaylines(struct comp_data *cd)
383384 iir [i ].delay = NULL ;
384385}
385386
386- static int eq_iir_setup (struct comp_data * cd , int nch )
387+ static int eq_iir_init_coef (struct sof_eq_iir_config * config ,
388+ struct iir_state_df2t * iir , int nch )
387389{
388- struct iir_state_df2t * iir = cd -> iir ;
389- struct sof_eq_iir_config * config = cd -> config ;
390390 struct sof_eq_iir_header_df2t * lookup [SOF_EQ_IIR_MAX_RESPONSES ];
391391 struct sof_eq_iir_header_df2t * eq ;
392- int64_t * iir_delay ;
393- int32_t * coef_data , * assign_response ;
394- size_t s ;
395- size_t size_sum = 0 ;
392+ int32_t * assign_response ;
393+ int32_t * coef_data ;
394+ int size_sum = 0 ;
395+ int resp = 0 ;
396396 int i ;
397397 int j ;
398- int resp ;
399-
400- /* Free existing IIR channels data if it was allocated */
401- eq_iir_free_delaylines (cd );
398+ int s ;
402399
403- trace_eq ("eq_iir_setup() , "
404- "channels_in_config = %u, number_of_responses = %u" ,
405- config -> channels_in_config , config -> number_of_responses );
400+ trace_eq ("eq_iir_init_coef(), response assign for %u channels , "
401+ "%u responses" , config -> channels_in_config ,
402+ config -> number_of_responses );
406403
407404 /* Sanity checks */
408405 if (nch > PLATFORM_MAX_CHANNELS ||
409406 config -> channels_in_config > PLATFORM_MAX_CHANNELS ||
410407 !config -> channels_in_config ) {
411- trace_eq_error ("eq_iir_setup() error: "
412- "invalid nch or channels_in_config" );
408+ trace_eq_error ("eq_iir_init_coef(), invalid channels count" );
413409 return - EINVAL ;
414410 }
415411 if (config -> number_of_responses > SOF_EQ_IIR_MAX_RESPONSES ) {
416- trace_eq_error ("eq_iir_setup() error: number_of_responses"
417- " > SOF_EQ_IIR_MAX_RESPONSES" );
412+ trace_eq_error ("eq_iir_init_coef(), # of resp exceeds max" );
418413 return - EINVAL ;
419414 }
420415
@@ -438,15 +433,13 @@ static int eq_iir_setup(struct comp_data *cd, int nch)
438433 /* Initialize 1st phase */
439434 for (i = 0 ; i < nch ; i ++ ) {
440435 /* Check for not reading past blob response to channel assign
441- * map. If the blob has smaller channel map then apply for
442- * additional channels the response that was used for the first
443- * channel. This allows to use mono blobs to setup multi
444- * channel equalization without stopping to an error .
436+ * map. The previous channel response is assigned for any
437+ * additional channels in the stream. It allows to use single
438+ * channel configuration to setup multi channel equalization
439+ * with the same response .
445440 */
446441 if (i < config -> channels_in_config )
447442 resp = assign_response [i ];
448- else
449- resp = assign_response [0 ];
450443
451444 if (resp < 0 ) {
452445 /* Initialize EQ channel to bypass and continue with
@@ -461,52 +454,66 @@ static int eq_iir_setup(struct comp_data *cd, int nch)
461454
462455 /* Initialize EQ coefficients */
463456 eq = lookup [resp ];
464- s = iir_init_coef_df2t ( & iir [ i ], eq );
465- if (s > 0 )
457+ s = iir_delay_size_df2t ( eq );
458+ if (s > 0 ) {
466459 size_sum += s ;
467- else
460+ } else {
468461 return - EINVAL ;
462+ }
469463
470- trace_eq ("eq_iir_setup(), "
471- "ch = %d initialized to response = %d" , i , resp );
464+ iir_init_coef_df2t (& iir [i ], eq );
465+ trace_eq ("eq_iir_init_coef(), ch %d is set to response %d" ,
466+ i , resp );
472467 }
473468
474- /* If all channels were set to bypass there's no need to
475- * allocate delay. Just return with success.
476- */
477- cd -> iir_delay = NULL ;
478- cd -> iir_delay_size = size_sum ;
479- if (!size_sum )
480- return 0 ;
481- /* Allocate all IIR channels data in a big chunk and clear it */
482- cd -> iir_delay = rzalloc (RZONE_RUNTIME , SOF_MEM_CAPS_RAM , size_sum );
483- if (!cd -> iir_delay )
484- return - ENOMEM ;
469+ return size_sum ;
470+ }
485471
486- memset (cd -> iir_delay , 0 , size_sum );
472+ static void eq_iir_init_delay (struct iir_state_df2t * iir ,
473+ int64_t * delay_start , int nch )
474+ {
475+ int64_t * delay = delay_start ;
476+ int i ;
487477
488- /* Initialize 2nd phase to set EQ delay lines pointers */
489- iir_delay = cd -> iir_delay ;
478+ /* Initialize second phase to set EQ delay lines pointers. A
479+ * bypass mode filter is indicated by biquads count of zero.
480+ */
490481 for (i = 0 ; i < nch ; i ++ ) {
491- resp = assign_response [i ];
492- if (resp >= 0 )
493- iir_init_delay_df2t (& iir [i ], & iir_delay );
482+ if (iir [i ].biquads > 0 )
483+ iir_init_delay_df2t (& iir [i ], & delay );
494484 }
495- return 0 ;
496485}
497486
498- static int eq_iir_switch_store (struct iir_state_df2t iir [],
499- struct sof_eq_iir_config * config ,
500- uint32_t ch , int32_t response )
487+ static int eq_iir_setup (struct comp_data * cd , int nch )
501488{
502- /* Copy assign response from update. The EQ is initialized later
503- * when all channels have been updated.
489+ int delay_size ;
490+
491+ /* Free existing IIR channels data if it was allocated */
492+ eq_iir_free_delaylines (cd );
493+
494+ /* Set coefficients for each channel EQ from coefficient blob */
495+ delay_size = eq_iir_init_coef (cd -> config , cd -> iir , nch );
496+ if (delay_size < 0 )
497+ return delay_size ; /* Contains error code */
498+
499+ /* If all channels were set to bypass there's no need to
500+ * allocate delay. Just return with success.
504501 */
505- if (!config || ch >= config -> channels_in_config )
506- return - EINVAL ;
502+ if (!delay_size )
503+ return 0 ;
504+
505+ /* Allocate all IIR channels data in a big chunk and clear it */
506+ cd -> iir_delay = rzalloc (RZONE_RUNTIME , SOF_MEM_CAPS_RAM , delay_size );
507+ if (!cd -> iir_delay ) {
508+ trace_eq_error ("eq_iir_setup(), delay allocation fail" );
509+ return - ENOMEM ;
510+ }
507511
508- config -> data [ch ] = response ;
512+ memset (cd -> iir_delay , 0 , delay_size );
513+ cd -> iir_delay_size = delay_size ;
509514
515+ /* Assign delay line to each channel EQ */
516+ eq_iir_init_delay (cd -> iir , cd -> iir_delay , nch );
510517 return 0 ;
511518}
512519
@@ -563,6 +570,7 @@ static struct comp_dev *eq_iir_new(struct sof_ipc_comp *comp)
563570 cd -> iir_delay = NULL ;
564571 cd -> iir_delay_size = 0 ;
565572 cd -> config = NULL ;
573+ cd -> config_new = NULL ;
566574
567575 /* Allocate and make a copy of the coefficients blob and reset IIR. If
568576 * the EQ is configured later in run-time the size is zero.
@@ -594,6 +602,7 @@ static void eq_iir_free(struct comp_dev *dev)
594602
595603 eq_iir_free_delaylines (cd );
596604 eq_iir_free_parameters (& cd -> config );
605+ eq_iir_free_parameters (& cd -> config_new );
597606
598607 rfree (cd );
599608 rfree (dev );
@@ -654,86 +663,58 @@ static int iir_cmd_set_data(struct comp_dev *dev,
654663 struct sof_ipc_ctrl_data * cdata )
655664{
656665 struct comp_data * cd = comp_get_drvdata (dev );
657- struct sof_ipc_ctrl_value_comp * compv ;
658- struct sof_eq_iir_config * cfg ;
666+ struct sof_eq_iir_config * request ;
659667 size_t bs ;
660- int i ;
661668 int ret = 0 ;
662669
663670 switch (cdata -> cmd ) {
664- case SOF_CTRL_CMD_ENUM :
665- trace_eq_with_ids (dev , "iir_cmd_set_data(), SOF_CTRL_CMD_ENUM" );
666- compv = (struct sof_ipc_ctrl_value_comp * )cdata -> data -> data ;
667- if (cdata -> index == SOF_EQ_IIR_IDX_SWITCH ) {
668- for (i = 0 ; i < (int )cdata -> num_elems ; i ++ ) {
669- trace_eq_with_ids (dev , "iir_cmd_set_data(),"
670- "SOF_EQ_IIR_IDX_SWITCH, "
671- "compv index = %u, "
672- "svalue = %u" ,
673- compv [i ].index ,
674- compv [i ].svalue );
675- ret = eq_iir_switch_store (cd -> iir ,
676- cd -> config ,
677- compv [i ].index ,
678- compv [i ].svalue );
679- if (ret < 0 ) {
680- trace_eq_error_with_ids (dev ,
681- "iir_cmd_set_data() "
682- "error:"
683- "eq_iir_switch_store()"
684- " failed" );
685- return - EINVAL ;
686- }
687- }
688- } else {
689- trace_eq_error_with_ids (dev , "iir_cmd_set_data() error:"
690- "invalid cdata->index = %u" ,
691- cdata -> index );
692- return - EINVAL ;
693- }
694- break ;
695671 case SOF_CTRL_CMD_BINARY :
696672 trace_eq_with_ids (dev , "iir_cmd_set_data(), SOF_CTRL_CMD_BINARY" );
697673
698- if (dev -> state != COMP_STATE_READY ) {
699- /* It is a valid request but currently this is not
700- * supported during playback/capture. The driver will
701- * re-send data in next resume when idle and the new
702- * EQ configuration will be used when playback/capture
703- * starts.
704- */
705- trace_eq_error_with_ids (dev , "iir_cmd_set_data() error: "
706- "driver is busy" );
707- return - EBUSY ;
708- }
709-
710- /* Check and free old config */
711- eq_iir_free_parameters (& cd -> config );
712-
713- /* Copy new config, find size from header */
714- cfg = (struct sof_eq_iir_config * )cdata -> data -> data ;
715- bs = cfg -> size ;
716- trace_eq_with_ids (dev , "iir_cmd_set_data(), blob size = %u" ,
717- bs );
674+ /* Find size from header */
675+ request = (struct sof_eq_iir_config * )cdata -> data -> data ;
676+ bs = request -> size ;
718677 if (bs > SOF_EQ_IIR_MAX_SIZE || bs == 0 ) {
719678 trace_eq_error_with_ids (dev , "iir_cmd_set_data() error: "
720679 "invalid blob size" );
721680 return - EINVAL ;
722681 }
723682
683+ /* Check that there is no work-in-progress previous request */
684+ if (cd -> config_new ) {
685+ trace_eq_error_with_ids (dev , "iir_cmd_set_data(), busy with previous" );
686+ return - EBUSY ;
687+ }
688+
724689 /* Allocate and make a copy of the blob and setup IIR */
725- cd -> config = rzalloc (RZONE_RUNTIME , SOF_MEM_CAPS_RAM , bs );
726- if (!cd -> config ) {
727- trace_eq_error_with_ids (dev , "iir_cmd_set_data() error: "
728- "alloc failed" );
690+ cd -> config_new = rzalloc (RZONE_RUNTIME , SOF_MEM_CAPS_RAM , bs );
691+ if (!cd -> config_new ) {
692+ trace_eq_error_with_ids (dev , "iir_cmd_set_data(), alloc fail" );
729693 return - EINVAL ;
730694 }
731695
732- /* Just copy the configurate. The EQ will be initialized in
733- * prepare().
696+ /* Copy the configuration. If the component state is ready
697+ * the EQ will initialize in prepare().
734698 */
735- ret = memcpy_s (cd -> config , bs , cdata -> data -> data , bs );
699+ ret = memcpy_s (cd -> config_new , bs , cdata -> data -> data , bs );
736700 assert (!ret );
701+
702+ /* If component state is READY we can omit old configuration
703+ * immediately. When in playback/capture the new configuration
704+ * presence is checked in copy().
705+ */
706+ if (dev -> state == COMP_STATE_READY )
707+ eq_iir_free_parameters (& cd -> config );
708+
709+ /* If there is no existing configuration the received can
710+ * be set to current immediately. It will be applied in
711+ * prepare() when streaming starts.
712+ */
713+ if (!cd -> config ) {
714+ cd -> config = cd -> config_new ;
715+ cd -> config_new = NULL ;
716+ }
717+
737718 break ;
738719 default :
739720 trace_eq_error_with_ids (dev , "iir_cmd_set_data() error: "
@@ -761,12 +742,6 @@ static int eq_iir_cmd(struct comp_dev *dev, int cmd, void *data,
761742 case COMP_CMD_GET_DATA :
762743 ret = iir_cmd_get_data (dev , cdata , max_data_size );
763744 break ;
764- case COMP_CMD_SET_VALUE :
765- trace_eq_with_ids (dev , "eq_iir_cmd(), COMP_CMD_SET_VALUE" );
766- break ;
767- case COMP_CMD_GET_VALUE :
768- trace_eq_with_ids (dev , "eq_iir_cmd(), COMP_CMD_GET_VALUE" );
769- break ;
770745 default :
771746 trace_eq_error_with_ids (dev , "eq_iir_cmd() error: "
772747 "invalid command" );
@@ -796,6 +771,18 @@ static int eq_iir_copy(struct comp_dev *dev)
796771
797772 tracev_eq_with_ids (dev , "eq_iir_copy()" );
798773
774+ /* Check for changed configuration */
775+ if (cd -> config_new ) {
776+ eq_iir_free_parameters (& cd -> config );
777+ cd -> config = cd -> config_new ;
778+ cd -> config_new = NULL ;
779+ ret = eq_iir_setup (cd , dev -> params .channels );
780+ if (ret < 0 ) {
781+ trace_eq_error_with_ids (dev , "eq_iir_copy(), failed IIR setup" );
782+ return ret ;
783+ }
784+ }
785+
799786 /* Get source, sink, number of frames etc. to process. */
800787 ret = comp_get_copy_limits (dev , & cl );
801788 if (ret < 0 ) {
@@ -919,12 +906,18 @@ static int eq_iir_reset(struct comp_dev *dev)
919906static void eq_iir_cache (struct comp_dev * dev , int cmd )
920907{
921908 struct comp_data * cd ;
909+ struct sof_eq_iir_config * cn ;
922910
923911 switch (cmd ) {
924912 case CACHE_WRITEBACK_INV :
925913 trace_eq_with_ids (dev , "eq_iir_cache(), CACHE_WRITEBACK_INV" );
926914
927915 cd = comp_get_drvdata (dev );
916+ if (cd -> config_new ) {
917+ cn = cd -> config_new ;
918+ dcache_writeback_invalidate_region (cn , cn -> size );
919+ }
920+
928921 if (cd -> config )
929922 dcache_writeback_invalidate_region (cd -> config ,
930923 cd -> config -> size );
@@ -955,6 +948,9 @@ static void eq_iir_cache(struct comp_dev *dev, int cmd)
955948 if (cd -> config )
956949 dcache_invalidate_region (cd -> config ,
957950 cd -> config -> size );
951+ if (cd -> config_new )
952+ dcache_invalidate_region (cd -> config_new ,
953+ cd -> config_new -> size );
958954 break ;
959955 }
960956}
0 commit comments