2015-10-07 11:31:52 +01:00
/*
* skl - topology . c - Implements Platform component ALSA controls / widget
* handlers .
*
* Copyright ( C ) 2014 - 2015 Intel Corp
* Author : Jeeja KP < jeeja . kp @ intel . com >
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as version 2 , as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*/
# include <linux/slab.h>
# include <linux/types.h>
# include <linux/firmware.h>
# include <sound/soc.h>
# include <sound/soc-topology.h>
# include "skl-sst-dsp.h"
# include "skl-sst-ipc.h"
# include "skl-topology.h"
# include "skl.h"
# include "skl-tplg-interface.h"
2015-12-03 23:29:50 +05:30
# include "../common/sst-dsp.h"
# include "../common/sst-dsp-priv.h"
2015-10-07 11:31:52 +01:00
2015-10-07 11:31:53 +01:00
# define SKL_CH_FIXUP_MASK (1 << 0)
# define SKL_RATE_FIXUP_MASK (1 << 1)
# define SKL_FMT_FIXUP_MASK (1 << 2)
2015-10-07 11:31:52 +01:00
/*
* SKL DSP driver modelling uses only few DAPM widgets so for rest we will
* ignore . This helpers checks if the SKL driver handles this widget type
*/
static int is_skl_dsp_widget_type ( struct snd_soc_dapm_widget * w )
{
switch ( w - > id ) {
case snd_soc_dapm_dai_link :
case snd_soc_dapm_dai_in :
case snd_soc_dapm_aif_in :
case snd_soc_dapm_aif_out :
case snd_soc_dapm_dai_out :
case snd_soc_dapm_switch :
return false ;
default :
return true ;
}
}
/*
* Each pipelines needs memory to be allocated . Check if we have free memory
2016-02-03 17:59:47 +05:30
* from available pool .
2015-10-07 11:31:52 +01:00
*/
2016-02-03 17:59:47 +05:30
static bool skl_is_pipe_mem_avail ( struct skl * skl ,
2015-10-07 11:31:52 +01:00
struct skl_module_cfg * mconfig )
{
struct skl_sst * ctx = skl - > skl_sst ;
if ( skl - > resource . mem + mconfig - > pipe - > memory_pages >
skl - > resource . max_mem ) {
dev_err ( ctx - > dev ,
" %s: module_id %d instance %d \n " , __func__ ,
mconfig - > id . module_id ,
mconfig - > id . instance_id ) ;
dev_err ( ctx - > dev ,
" exceeds ppl memory available %d mem %d \n " ,
skl - > resource . max_mem , skl - > resource . mem ) ;
return false ;
2016-02-03 17:59:47 +05:30
} else {
return true ;
2015-10-07 11:31:52 +01:00
}
2016-02-03 17:59:47 +05:30
}
2015-10-07 11:31:52 +01:00
2016-02-03 17:59:47 +05:30
/*
* Add the mem to the mem pool . This is freed when pipe is deleted .
* Note : DSP does actual memory management we only keep track for complete
* pool
*/
static void skl_tplg_alloc_pipe_mem ( struct skl * skl ,
struct skl_module_cfg * mconfig )
{
2015-10-07 11:31:52 +01:00
skl - > resource . mem + = mconfig - > pipe - > memory_pages ;
}
/*
* Pipeline needs needs DSP CPU resources for computation , this is
* quantified in MCPS ( Million Clocks Per Second ) required for module / pipe
*
* Each pipelines needs mcps to be allocated . Check if we have mcps for this
2016-02-03 17:59:47 +05:30
* pipe .
2015-10-07 11:31:52 +01:00
*/
2016-02-03 17:59:47 +05:30
static bool skl_is_pipe_mcps_avail ( struct skl * skl ,
2015-10-07 11:31:52 +01:00
struct skl_module_cfg * mconfig )
{
struct skl_sst * ctx = skl - > skl_sst ;
if ( skl - > resource . mcps + mconfig - > mcps > skl - > resource . max_mcps ) {
dev_err ( ctx - > dev ,
" %s: module_id %d instance %d \n " , __func__ ,
mconfig - > id . module_id , mconfig - > id . instance_id ) ;
dev_err ( ctx - > dev ,
2016-02-03 17:59:46 +05:30
" exceeds ppl mcps available %d > mem %d \n " ,
2015-10-07 11:31:52 +01:00
skl - > resource . max_mcps , skl - > resource . mcps ) ;
return false ;
2016-02-03 17:59:47 +05:30
} else {
return true ;
2015-10-07 11:31:52 +01:00
}
2016-02-03 17:59:47 +05:30
}
2015-10-07 11:31:52 +01:00
2016-02-03 17:59:47 +05:30
static void skl_tplg_alloc_pipe_mcps ( struct skl * skl ,
struct skl_module_cfg * mconfig )
{
2015-10-07 11:31:52 +01:00
skl - > resource . mcps + = mconfig - > mcps ;
}
/*
* Free the mcps when tearing down
*/
static void
skl_tplg_free_pipe_mcps ( struct skl * skl , struct skl_module_cfg * mconfig )
{
skl - > resource . mcps - = mconfig - > mcps ;
}
/*
* Free the memory when tearing down
*/
static void
skl_tplg_free_pipe_mem ( struct skl * skl , struct skl_module_cfg * mconfig )
{
skl - > resource . mem - = mconfig - > pipe - > memory_pages ;
}
2015-10-07 11:31:53 +01:00
static void skl_dump_mconfig ( struct skl_sst * ctx ,
struct skl_module_cfg * mcfg )
{
dev_dbg ( ctx - > dev , " Dumping config \n " ) ;
dev_dbg ( ctx - > dev , " Input Format: \n " ) ;
2015-10-27 09:22:55 +09:00
dev_dbg ( ctx - > dev , " channels = %d \n " , mcfg - > in_fmt [ 0 ] . channels ) ;
dev_dbg ( ctx - > dev , " s_freq = %d \n " , mcfg - > in_fmt [ 0 ] . s_freq ) ;
dev_dbg ( ctx - > dev , " ch_cfg = %d \n " , mcfg - > in_fmt [ 0 ] . ch_cfg ) ;
dev_dbg ( ctx - > dev , " valid bit depth = %d \n " , mcfg - > in_fmt [ 0 ] . valid_bit_depth ) ;
2015-10-07 11:31:53 +01:00
dev_dbg ( ctx - > dev , " Output Format: \n " ) ;
2015-10-27 09:22:55 +09:00
dev_dbg ( ctx - > dev , " channels = %d \n " , mcfg - > out_fmt [ 0 ] . channels ) ;
dev_dbg ( ctx - > dev , " s_freq = %d \n " , mcfg - > out_fmt [ 0 ] . s_freq ) ;
dev_dbg ( ctx - > dev , " valid bit depth = %d \n " , mcfg - > out_fmt [ 0 ] . valid_bit_depth ) ;
dev_dbg ( ctx - > dev , " ch_cfg = %d \n " , mcfg - > out_fmt [ 0 ] . ch_cfg ) ;
2015-10-07 11:31:53 +01:00
}
2016-04-14 10:07:36 +05:30
static void skl_tplg_update_chmap ( struct skl_module_fmt * fmt , int chs )
{
int slot_map = 0xFFFFFFFF ;
int start_slot = 0 ;
int i ;
for ( i = 0 ; i < chs ; i + + ) {
/*
* For 2 channels with starting slot as 0 , slot map will
* look like 0xFFFFFF10 .
*/
slot_map & = ( ~ ( 0xF < < ( 4 * i ) ) | ( start_slot < < ( 4 * i ) ) ) ;
start_slot + + ;
}
fmt - > ch_map = slot_map ;
}
2015-10-07 11:31:53 +01:00
static void skl_tplg_update_params ( struct skl_module_fmt * fmt ,
struct skl_pipe_params * params , int fixup )
{
if ( fixup & SKL_RATE_FIXUP_MASK )
fmt - > s_freq = params - > s_freq ;
2016-04-14 10:07:36 +05:30
if ( fixup & SKL_CH_FIXUP_MASK ) {
2015-10-07 11:31:53 +01:00
fmt - > channels = params - > ch ;
2016-04-14 10:07:36 +05:30
skl_tplg_update_chmap ( fmt , fmt - > channels ) ;
}
2015-11-23 22:26:25 +05:30
if ( fixup & SKL_FMT_FIXUP_MASK ) {
fmt - > valid_bit_depth = skl_get_bit_depth ( params - > s_fmt ) ;
/*
* 16 bit is 16 bit container whereas 24 bit is in 32 bit
* container so update bit depth accordingly
*/
switch ( fmt - > valid_bit_depth ) {
case SKL_DEPTH_16BIT :
fmt - > bit_depth = fmt - > valid_bit_depth ;
break ;
default :
fmt - > bit_depth = SKL_DEPTH_32BIT ;
break ;
}
}
2015-10-07 11:31:53 +01:00
}
/*
* A pipeline may have modules which impact the pcm parameters , like SRC ,
* channel converter , format converter .
* We need to calculate the output params by applying the ' fixup '
* Topology will tell driver which type of fixup is to be applied by
* supplying the fixup mask , so based on that we calculate the output
*
* Now In FE the pcm hw_params is source / target format . Same is applicable
* for BE with its hw_params invoked .
* here based on FE , BE pipeline and direction we calculate the input and
* outfix and then apply that for a module
*/
static void skl_tplg_update_params_fixup ( struct skl_module_cfg * m_cfg ,
struct skl_pipe_params * params , bool is_fe )
{
int in_fixup , out_fixup ;
struct skl_module_fmt * in_fmt , * out_fmt ;
2015-10-27 09:22:55 +09:00
/* Fixups will be applied to pin 0 only */
in_fmt = & m_cfg - > in_fmt [ 0 ] ;
out_fmt = & m_cfg - > out_fmt [ 0 ] ;
2015-10-07 11:31:53 +01:00
if ( params - > stream = = SNDRV_PCM_STREAM_PLAYBACK ) {
if ( is_fe ) {
in_fixup = m_cfg - > params_fixup ;
out_fixup = ( ~ m_cfg - > converter ) &
m_cfg - > params_fixup ;
} else {
out_fixup = m_cfg - > params_fixup ;
in_fixup = ( ~ m_cfg - > converter ) &
m_cfg - > params_fixup ;
}
} else {
if ( is_fe ) {
out_fixup = m_cfg - > params_fixup ;
in_fixup = ( ~ m_cfg - > converter ) &
m_cfg - > params_fixup ;
} else {
in_fixup = m_cfg - > params_fixup ;
out_fixup = ( ~ m_cfg - > converter ) &
m_cfg - > params_fixup ;
}
}
skl_tplg_update_params ( in_fmt , params , in_fixup ) ;
skl_tplg_update_params ( out_fmt , params , out_fixup ) ;
}
/*
* A module needs input and output buffers , which are dependent upon pcm
* params , so once we have calculate params , we need buffer calculation as
* well .
*/
static void skl_tplg_update_buffer_size ( struct skl_sst * ctx ,
struct skl_module_cfg * mcfg )
{
int multiplier = 1 ;
2015-10-27 09:22:55 +09:00
struct skl_module_fmt * in_fmt , * out_fmt ;
2016-04-12 10:31:23 +05:30
int in_rate , out_rate ;
2015-10-27 09:22:55 +09:00
/* Since fixups is applied to pin 0 only, ibs, obs needs
* change for pin 0 only
*/
in_fmt = & mcfg - > in_fmt [ 0 ] ;
out_fmt = & mcfg - > out_fmt [ 0 ] ;
2015-10-07 11:31:53 +01:00
if ( mcfg - > m_type = = SKL_MODULE_TYPE_SRCINT )
multiplier = 5 ;
2016-04-12 10:31:23 +05:30
if ( in_fmt - > s_freq % 1000 )
in_rate = ( in_fmt - > s_freq / 1000 ) + 1 ;
else
in_rate = ( in_fmt - > s_freq / 1000 ) ;
mcfg - > ibs = in_rate * ( mcfg - > in_fmt - > channels ) *
( mcfg - > in_fmt - > bit_depth > > 3 ) *
multiplier ;
if ( mcfg - > out_fmt - > s_freq % 1000 )
out_rate = ( mcfg - > out_fmt - > s_freq / 1000 ) + 1 ;
else
out_rate = ( mcfg - > out_fmt - > s_freq / 1000 ) ;
mcfg - > obs = out_rate * ( mcfg - > out_fmt - > channels ) *
( mcfg - > out_fmt - > bit_depth > > 3 ) *
multiplier ;
2015-10-07 11:31:53 +01:00
}
2016-02-05 12:19:10 +05:30
static int skl_tplg_update_be_blob ( struct snd_soc_dapm_widget * w ,
struct skl_sst * ctx )
{
struct skl_module_cfg * m_cfg = w - > priv ;
int link_type , dir ;
u32 ch , s_freq , s_fmt ;
struct nhlt_specific_cfg * cfg ;
struct skl * skl = get_skl_ctx ( ctx - > dev ) ;
/* check if we already have blob */
if ( m_cfg - > formats_config . caps_size > 0 )
return 0 ;
2016-03-01 07:59:10 +05:30
dev_dbg ( ctx - > dev , " Applying default cfg blob \n " ) ;
2016-02-05 12:19:10 +05:30
switch ( m_cfg - > dev_type ) {
case SKL_DEVICE_DMIC :
link_type = NHLT_LINK_DMIC ;
2016-03-01 07:59:10 +05:30
dir = SNDRV_PCM_STREAM_CAPTURE ;
2016-02-05 12:19:10 +05:30
s_freq = m_cfg - > in_fmt [ 0 ] . s_freq ;
s_fmt = m_cfg - > in_fmt [ 0 ] . bit_depth ;
ch = m_cfg - > in_fmt [ 0 ] . channels ;
break ;
case SKL_DEVICE_I2S :
link_type = NHLT_LINK_SSP ;
if ( m_cfg - > hw_conn_type = = SKL_CONN_SOURCE ) {
2016-03-01 07:59:10 +05:30
dir = SNDRV_PCM_STREAM_PLAYBACK ;
2016-02-05 12:19:10 +05:30
s_freq = m_cfg - > out_fmt [ 0 ] . s_freq ;
s_fmt = m_cfg - > out_fmt [ 0 ] . bit_depth ;
ch = m_cfg - > out_fmt [ 0 ] . channels ;
2016-03-01 07:59:10 +05:30
} else {
dir = SNDRV_PCM_STREAM_CAPTURE ;
s_freq = m_cfg - > in_fmt [ 0 ] . s_freq ;
s_fmt = m_cfg - > in_fmt [ 0 ] . bit_depth ;
ch = m_cfg - > in_fmt [ 0 ] . channels ;
2016-02-05 12:19:10 +05:30
}
break ;
default :
return - EINVAL ;
}
/* update the blob based on virtual bus_id and default params */
cfg = skl_get_ep_blob ( skl , m_cfg - > vbus_id , link_type ,
s_fmt , ch , s_freq , dir ) ;
if ( cfg ) {
m_cfg - > formats_config . caps_size = cfg - > size ;
m_cfg - > formats_config . caps = ( u32 * ) & cfg - > caps ;
} else {
dev_err ( ctx - > dev , " Blob NULL for id %x type %d dirn %d \n " ,
m_cfg - > vbus_id , link_type , dir ) ;
dev_err ( ctx - > dev , " PCM: ch %d, freq %d, fmt %d \n " ,
ch , s_freq , s_fmt ) ;
return - EIO ;
}
return 0 ;
}
2015-10-07 11:31:53 +01:00
static void skl_tplg_update_module_params ( struct snd_soc_dapm_widget * w ,
struct skl_sst * ctx )
{
struct skl_module_cfg * m_cfg = w - > priv ;
struct skl_pipe_params * params = m_cfg - > pipe - > p_params ;
int p_conn_type = m_cfg - > pipe - > conn_type ;
bool is_fe ;
if ( ! m_cfg - > params_fixup )
return ;
dev_dbg ( ctx - > dev , " Mconfig for widget=%s BEFORE updation \n " ,
w - > name ) ;
skl_dump_mconfig ( ctx , m_cfg ) ;
if ( p_conn_type = = SKL_PIPE_CONN_TYPE_FE )
is_fe = true ;
else
is_fe = false ;
skl_tplg_update_params_fixup ( m_cfg , params , is_fe ) ;
skl_tplg_update_buffer_size ( ctx , m_cfg ) ;
dev_dbg ( ctx - > dev , " Mconfig for widget=%s AFTER updation \n " ,
w - > name ) ;
skl_dump_mconfig ( ctx , m_cfg ) ;
}
2015-11-28 15:01:49 +05:30
/*
* some modules can have multiple params set from user control and
* need to be set after module is initialized . If set_param flag is
* set module params will be done after module is initialised .
*/
static int skl_tplg_set_module_params ( struct snd_soc_dapm_widget * w ,
struct skl_sst * ctx )
{
int i , ret ;
struct skl_module_cfg * mconfig = w - > priv ;
const struct snd_kcontrol_new * k ;
struct soc_bytes_ext * sb ;
struct skl_algo_data * bc ;
struct skl_specific_cfg * sp_cfg ;
if ( mconfig - > formats_config . caps_size > 0 & &
2015-12-03 23:29:53 +05:30
mconfig - > formats_config . set_params = = SKL_PARAM_SET ) {
2015-11-28 15:01:49 +05:30
sp_cfg = & mconfig - > formats_config ;
ret = skl_set_module_params ( ctx , sp_cfg - > caps ,
sp_cfg - > caps_size ,
sp_cfg - > param_id , mconfig ) ;
if ( ret < 0 )
return ret ;
}
for ( i = 0 ; i < w - > num_kcontrols ; i + + ) {
k = & w - > kcontrol_news [ i ] ;
if ( k - > access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK ) {
sb = ( void * ) k - > private_value ;
bc = ( struct skl_algo_data * ) sb - > dobj . private ;
2015-12-03 23:29:53 +05:30
if ( bc - > set_params = = SKL_PARAM_SET ) {
2015-11-28 15:01:49 +05:30
ret = skl_set_module_params ( ctx ,
( u32 * ) bc - > params , bc - > max ,
bc - > param_id , mconfig ) ;
if ( ret < 0 )
return ret ;
}
}
}
return 0 ;
}
/*
* some module param can set from user control and this is required as
* when module is initailzed . if module param is required in init it is
* identifed by set_param flag . if set_param flag is not set , then this
* parameter needs to set as part of module init .
*/
static int skl_tplg_set_module_init_data ( struct snd_soc_dapm_widget * w )
{
const struct snd_kcontrol_new * k ;
struct soc_bytes_ext * sb ;
struct skl_algo_data * bc ;
struct skl_module_cfg * mconfig = w - > priv ;
int i ;
for ( i = 0 ; i < w - > num_kcontrols ; i + + ) {
k = & w - > kcontrol_news [ i ] ;
if ( k - > access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK ) {
sb = ( struct soc_bytes_ext * ) k - > private_value ;
bc = ( struct skl_algo_data * ) sb - > dobj . private ;
2015-12-03 23:29:53 +05:30
if ( bc - > set_params ! = SKL_PARAM_INIT )
2015-11-28 15:01:49 +05:30
continue ;
mconfig - > formats_config . caps = ( u32 * ) & bc - > params ;
mconfig - > formats_config . caps_size = bc - > max ;
break ;
}
}
return 0 ;
}
2015-10-07 11:31:52 +01:00
/*
* Inside a pipe instance , we can have various modules . These modules need
* to instantiated in DSP by invoking INIT_MODULE IPC , which is achieved by
* skl_init_module ( ) routine , so invoke that for all modules in a pipeline
*/
static int
skl_tplg_init_pipe_modules ( struct skl * skl , struct skl_pipe * pipe )
{
struct skl_pipe_module * w_module ;
struct snd_soc_dapm_widget * w ;
struct skl_module_cfg * mconfig ;
struct skl_sst * ctx = skl - > skl_sst ;
int ret = 0 ;
list_for_each_entry ( w_module , & pipe - > w_list , node ) {
w = w_module - > w ;
mconfig = w - > priv ;
/* check resource available */
2016-02-03 17:59:47 +05:30
if ( ! skl_is_pipe_mcps_avail ( skl , mconfig ) )
2015-10-07 11:31:52 +01:00
return - ENOMEM ;
2015-12-03 23:29:50 +05:30
if ( mconfig - > is_loadable & & ctx - > dsp - > fw_ops . load_mod ) {
ret = ctx - > dsp - > fw_ops . load_mod ( ctx - > dsp ,
mconfig - > id . module_id , mconfig - > guid ) ;
if ( ret < 0 )
return ret ;
2016-03-28 22:11:30 +05:30
mconfig - > m_state = SKL_MODULE_LOADED ;
2015-12-03 23:29:50 +05:30
}
2016-02-05 12:19:10 +05:30
/* update blob if blob is null for be with default value */
skl_tplg_update_be_blob ( w , ctx ) ;
2015-10-07 11:31:53 +01:00
/*
* apply fix / conversion to module params based on
* FE / BE params
*/
skl_tplg_update_module_params ( w , ctx ) ;
2015-11-28 15:01:49 +05:30
skl_tplg_set_module_init_data ( w ) ;
2015-11-28 15:01:47 +05:30
ret = skl_init_module ( ctx , mconfig ) ;
2015-10-07 11:31:52 +01:00
if ( ret < 0 )
return ret ;
2015-11-28 15:01:49 +05:30
2016-06-03 18:29:38 +05:30
skl_tplg_alloc_pipe_mcps ( skl , mconfig ) ;
2015-11-28 15:01:49 +05:30
ret = skl_tplg_set_module_params ( w , ctx ) ;
2015-10-07 11:31:52 +01:00
if ( ret < 0 )
return ret ;
}
return 0 ;
}
2015-10-07 11:31:54 +01:00
2015-12-03 23:29:50 +05:30
static int skl_tplg_unload_pipe_modules ( struct skl_sst * ctx ,
struct skl_pipe * pipe )
{
struct skl_pipe_module * w_module = NULL ;
struct skl_module_cfg * mconfig = NULL ;
list_for_each_entry ( w_module , & pipe - > w_list , node ) {
mconfig = w_module - > w - > priv ;
2016-03-28 22:11:30 +05:30
if ( mconfig - > is_loadable & & ctx - > dsp - > fw_ops . unload_mod & &
mconfig - > m_state > SKL_MODULE_UNINIT )
2015-12-03 23:29:50 +05:30
return ctx - > dsp - > fw_ops . unload_mod ( ctx - > dsp ,
mconfig - > id . module_id ) ;
}
/* no modules to unload in this path, so return */
return 0 ;
}
2015-10-07 11:31:54 +01:00
/*
* Mixer module represents a pipeline . So in the Pre - PMU event of mixer we
* need create the pipeline . So we do following :
* - check the resources
* - Create the pipeline
* - Initialize the modules in pipeline
* - finally bind all modules together
*/
static int skl_tplg_mixer_dapm_pre_pmu_event ( struct snd_soc_dapm_widget * w ,
struct skl * skl )
{
int ret ;
struct skl_module_cfg * mconfig = w - > priv ;
struct skl_pipe_module * w_module ;
struct skl_pipe * s_pipe = mconfig - > pipe ;
struct skl_module_cfg * src_module = NULL , * dst_module ;
struct skl_sst * ctx = skl - > skl_sst ;
/* check resource available */
2016-02-03 17:59:47 +05:30
if ( ! skl_is_pipe_mcps_avail ( skl , mconfig ) )
2015-10-07 11:31:54 +01:00
return - EBUSY ;
2016-02-03 17:59:47 +05:30
if ( ! skl_is_pipe_mem_avail ( skl , mconfig ) )
2015-10-07 11:31:54 +01:00
return - ENOMEM ;
/*
* Create a list of modules for pipe .
* This list contains modules from source to sink
*/
ret = skl_create_pipeline ( ctx , mconfig - > pipe ) ;
if ( ret < 0 )
return ret ;
2016-06-03 18:29:38 +05:30
skl_tplg_alloc_pipe_mem ( skl , mconfig ) ;
skl_tplg_alloc_pipe_mcps ( skl , mconfig ) ;
2015-10-07 11:31:54 +01:00
/* Init all pipe modules from source to sink */
ret = skl_tplg_init_pipe_modules ( skl , s_pipe ) ;
if ( ret < 0 )
return ret ;
/* Bind modules from source to sink */
list_for_each_entry ( w_module , & s_pipe - > w_list , node ) {
dst_module = w_module - > w - > priv ;
if ( src_module = = NULL ) {
src_module = dst_module ;
continue ;
}
ret = skl_bind_modules ( ctx , src_module , dst_module ) ;
if ( ret < 0 )
return ret ;
src_module = dst_module ;
}
return 0 ;
}
2016-02-05 12:19:08 +05:30
/*
* Some modules require params to be set after the module is bound to
* all pins connected .
*
* The module provider initializes set_param flag for such modules and we
* send params after binding
*/
static int skl_tplg_set_module_bind_params ( struct snd_soc_dapm_widget * w ,
struct skl_module_cfg * mcfg , struct skl_sst * ctx )
{
int i , ret ;
struct skl_module_cfg * mconfig = w - > priv ;
const struct snd_kcontrol_new * k ;
struct soc_bytes_ext * sb ;
struct skl_algo_data * bc ;
struct skl_specific_cfg * sp_cfg ;
/*
* check all out / in pins are in bind state .
* if so set the module param
*/
for ( i = 0 ; i < mcfg - > max_out_queue ; i + + ) {
if ( mcfg - > m_out_pin [ i ] . pin_state ! = SKL_PIN_BIND_DONE )
return 0 ;
}
for ( i = 0 ; i < mcfg - > max_in_queue ; i + + ) {
if ( mcfg - > m_in_pin [ i ] . pin_state ! = SKL_PIN_BIND_DONE )
return 0 ;
}
if ( mconfig - > formats_config . caps_size > 0 & &
mconfig - > formats_config . set_params = = SKL_PARAM_BIND ) {
sp_cfg = & mconfig - > formats_config ;
ret = skl_set_module_params ( ctx , sp_cfg - > caps ,
sp_cfg - > caps_size ,
sp_cfg - > param_id , mconfig ) ;
if ( ret < 0 )
return ret ;
}
for ( i = 0 ; i < w - > num_kcontrols ; i + + ) {
k = & w - > kcontrol_news [ i ] ;
if ( k - > access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK ) {
sb = ( void * ) k - > private_value ;
bc = ( struct skl_algo_data * ) sb - > dobj . private ;
if ( bc - > set_params = = SKL_PARAM_BIND ) {
ret = skl_set_module_params ( ctx ,
( u32 * ) bc - > params , bc - > max ,
bc - > param_id , mconfig ) ;
if ( ret < 0 )
return ret ;
}
}
}
return 0 ;
}
2015-10-27 09:22:52 +09:00
static int skl_tplg_bind_sinks ( struct snd_soc_dapm_widget * w ,
struct skl * skl ,
2016-02-03 17:59:51 +05:30
struct snd_soc_dapm_widget * src_w ,
2015-10-27 09:22:52 +09:00
struct skl_module_cfg * src_mconfig )
2015-10-07 11:31:54 +01:00
{
struct snd_soc_dapm_path * p ;
2015-11-13 19:22:11 +05:30
struct snd_soc_dapm_widget * sink = NULL , * next_sink = NULL ;
2015-10-27 09:22:52 +09:00
struct skl_module_cfg * sink_mconfig ;
2015-10-07 11:31:54 +01:00
struct skl_sst * ctx = skl - > skl_sst ;
2015-10-27 09:22:52 +09:00
int ret ;
2015-10-07 11:31:54 +01:00
2015-10-27 09:22:52 +09:00
snd_soc_dapm_widget_for_each_sink_path ( w , p ) {
2015-10-07 11:31:54 +01:00
if ( ! p - > connect )
continue ;
dev_dbg ( ctx - > dev , " %s: src widget=%s \n " , __func__ , w - > name ) ;
dev_dbg ( ctx - > dev , " %s: sink widget=%s \n " , __func__ , p - > sink - > name ) ;
2015-11-13 19:22:11 +05:30
next_sink = p - > sink ;
2016-02-03 17:59:51 +05:30
if ( ! is_skl_dsp_widget_type ( p - > sink ) )
return skl_tplg_bind_sinks ( p - > sink , skl , src_w , src_mconfig ) ;
2015-10-07 11:31:54 +01:00
/*
* here we will check widgets in sink pipelines , so that
* can be any widgets type and we are only interested if
* they are ones used for SKL so check that first
*/
if ( ( p - > sink - > priv ! = NULL ) & &
is_skl_dsp_widget_type ( p - > sink ) ) {
sink = p - > sink ;
sink_mconfig = sink - > priv ;
2016-02-05 12:19:08 +05:30
if ( src_mconfig - > m_state = = SKL_MODULE_UNINIT | |
sink_mconfig - > m_state = = SKL_MODULE_UNINIT )
continue ;
2015-10-07 11:31:54 +01:00
/* Bind source to sink, mixin is always source */
ret = skl_bind_modules ( ctx , src_mconfig , sink_mconfig ) ;
if ( ret )
return ret ;
2016-02-05 12:19:08 +05:30
/* set module params after bind */
skl_tplg_set_module_bind_params ( src_w , src_mconfig , ctx ) ;
skl_tplg_set_module_bind_params ( sink , sink_mconfig , ctx ) ;
2015-10-07 11:31:54 +01:00
/* Start sinks pipe first */
if ( sink_mconfig - > pipe - > state ! = SKL_PIPE_STARTED ) {
2015-10-27 09:22:53 +09:00
if ( sink_mconfig - > pipe - > conn_type ! =
SKL_PIPE_CONN_TYPE_FE )
ret = skl_run_pipe ( ctx ,
sink_mconfig - > pipe ) ;
2015-10-07 11:31:54 +01:00
if ( ret )
return ret ;
}
}
}
2015-10-27 09:22:52 +09:00
if ( ! sink )
2016-02-03 17:59:51 +05:30
return skl_tplg_bind_sinks ( next_sink , skl , src_w , src_mconfig ) ;
2015-10-27 09:22:52 +09:00
return 0 ;
}
/*
* A PGA represents a module in a pipeline . So in the Pre - PMU event of PGA
* we need to do following :
* - Bind to sink pipeline
* Since the sink pipes can be running and we don ' t get mixer event on
* connect for already running mixer , we need to find the sink pipes
* here and bind to them . This way dynamic connect works .
* - Start sink pipeline , if not running
* - Then run current pipe
*/
static int skl_tplg_pga_dapm_pre_pmu_event ( struct snd_soc_dapm_widget * w ,
struct skl * skl )
{
struct skl_module_cfg * src_mconfig ;
struct skl_sst * ctx = skl - > skl_sst ;
int ret = 0 ;
src_mconfig = w - > priv ;
/*
* find which sink it is connected to , bind with the sink ,
* if sink is not started , start sink pipe first , then start
* this pipe
*/
2016-02-03 17:59:51 +05:30
ret = skl_tplg_bind_sinks ( w , skl , w , src_mconfig ) ;
2015-10-07 11:31:54 +01:00
if ( ret )
return ret ;
/* Start source pipe last after starting all sinks */
2015-10-27 09:22:53 +09:00
if ( src_mconfig - > pipe - > conn_type ! = SKL_PIPE_CONN_TYPE_FE )
return skl_run_pipe ( ctx , src_mconfig - > pipe ) ;
2015-10-07 11:31:54 +01:00
return 0 ;
}
2015-10-27 09:22:52 +09:00
static struct snd_soc_dapm_widget * skl_get_src_dsp_widget (
struct snd_soc_dapm_widget * w , struct skl * skl )
{
struct snd_soc_dapm_path * p ;
struct snd_soc_dapm_widget * src_w = NULL ;
struct skl_sst * ctx = skl - > skl_sst ;
snd_soc_dapm_widget_for_each_source_path ( w , p ) {
src_w = p - > source ;
if ( ! p - > connect )
continue ;
dev_dbg ( ctx - > dev , " sink widget=%s \n " , w - > name ) ;
dev_dbg ( ctx - > dev , " src widget=%s \n " , p - > source - > name ) ;
/*
* here we will check widgets in sink pipelines , so that can
* be any widgets type and we are only interested if they are
* ones used for SKL so check that first
*/
if ( ( p - > source - > priv ! = NULL ) & &
is_skl_dsp_widget_type ( p - > source ) ) {
return p - > source ;
}
}
if ( src_w ! = NULL )
return skl_get_src_dsp_widget ( src_w , skl ) ;
return NULL ;
}
2015-10-07 11:31:54 +01:00
/*
* in the Post - PMU event of mixer we need to do following :
* - Check if this pipe is running
* - if not , then
* - bind this pipeline to its source pipeline
* if source pipe is already running , this means it is a dynamic
* connection and we need to bind only to that pipe
* - start this pipeline
*/
static int skl_tplg_mixer_dapm_post_pmu_event ( struct snd_soc_dapm_widget * w ,
struct skl * skl )
{
int ret = 0 ;
struct snd_soc_dapm_widget * source , * sink ;
struct skl_module_cfg * src_mconfig , * sink_mconfig ;
struct skl_sst * ctx = skl - > skl_sst ;
int src_pipe_started = 0 ;
sink = w ;
sink_mconfig = sink - > priv ;
/*
* If source pipe is already started , that means source is driving
* one more sink before this sink got connected , Since source is
* started , bind this sink to source and start this pipe .
*/
2015-10-27 09:22:52 +09:00
source = skl_get_src_dsp_widget ( w , skl ) ;
if ( source ! = NULL ) {
src_mconfig = source - > priv ;
sink_mconfig = sink - > priv ;
src_pipe_started = 1 ;
2015-10-07 11:31:54 +01:00
/*
2015-10-27 09:22:52 +09:00
* check pipe state , then no need to bind or start the
* pipe
2015-10-07 11:31:54 +01:00
*/
2015-10-27 09:22:52 +09:00
if ( src_mconfig - > pipe - > state ! = SKL_PIPE_STARTED )
src_pipe_started = 0 ;
2015-10-07 11:31:54 +01:00
}
if ( src_pipe_started ) {
ret = skl_bind_modules ( ctx , src_mconfig , sink_mconfig ) ;
if ( ret )
return ret ;
2016-02-05 12:19:08 +05:30
/* set module params after bind */
skl_tplg_set_module_bind_params ( source , src_mconfig , ctx ) ;
skl_tplg_set_module_bind_params ( sink , sink_mconfig , ctx ) ;
2015-10-27 09:22:53 +09:00
if ( sink_mconfig - > pipe - > conn_type ! = SKL_PIPE_CONN_TYPE_FE )
ret = skl_run_pipe ( ctx , sink_mconfig - > pipe ) ;
2015-10-07 11:31:54 +01:00
}
return ret ;
}
/*
* in the Pre - PMD event of mixer we need to do following :
* - Stop the pipe
* - find the source connections and remove that from dapm_path_list
* - unbind with source pipelines if still connected
*/
static int skl_tplg_mixer_dapm_pre_pmd_event ( struct snd_soc_dapm_widget * w ,
struct skl * skl )
{
struct skl_module_cfg * src_mconfig , * sink_mconfig ;
2015-10-27 09:22:51 +09:00
int ret = 0 , i ;
2015-10-07 11:31:54 +01:00
struct skl_sst * ctx = skl - > skl_sst ;
2015-10-27 09:22:51 +09:00
sink_mconfig = w - > priv ;
2015-10-07 11:31:54 +01:00
/* Stop the pipe */
ret = skl_stop_pipe ( ctx , sink_mconfig - > pipe ) ;
if ( ret )
return ret ;
2015-10-27 09:22:51 +09:00
for ( i = 0 ; i < sink_mconfig - > max_in_queue ; i + + ) {
if ( sink_mconfig - > m_in_pin [ i ] . pin_state = = SKL_PIN_BIND_DONE ) {
src_mconfig = sink_mconfig - > m_in_pin [ i ] . tgt_mcfg ;
if ( ! src_mconfig )
continue ;
/*
* If path_found = = 1 , that means pmd for source
* pipe has not occurred , source is connected to
* some other sink . so its responsibility of sink
* to unbind itself from source .
*/
ret = skl_stop_pipe ( ctx , src_mconfig - > pipe ) ;
if ( ret < 0 )
return ret ;
2015-10-07 11:31:54 +01:00
2015-10-27 09:22:51 +09:00
ret = skl_unbind_modules ( ctx ,
src_mconfig , sink_mconfig ) ;
2015-10-07 11:31:54 +01:00
}
}
return ret ;
}
/*
* in the Post - PMD event of mixer we need to do following :
* - Free the mcps used
* - Free the mem used
* - Unbind the modules within the pipeline
* - Delete the pipeline ( modules are not required to be explicitly
* deleted , pipeline delete is enough here
*/
static int skl_tplg_mixer_dapm_post_pmd_event ( struct snd_soc_dapm_widget * w ,
struct skl * skl )
{
struct skl_module_cfg * mconfig = w - > priv ;
struct skl_pipe_module * w_module ;
struct skl_module_cfg * src_module = NULL , * dst_module ;
struct skl_sst * ctx = skl - > skl_sst ;
struct skl_pipe * s_pipe = mconfig - > pipe ;
int ret = 0 ;
2016-06-03 18:29:38 +05:30
if ( s_pipe - > state = = SKL_PIPE_INVALID )
return - EINVAL ;
2015-10-07 11:31:54 +01:00
skl_tplg_free_pipe_mcps ( skl , mconfig ) ;
2015-11-23 22:26:29 +05:30
skl_tplg_free_pipe_mem ( skl , mconfig ) ;
2015-10-07 11:31:54 +01:00
list_for_each_entry ( w_module , & s_pipe - > w_list , node ) {
dst_module = w_module - > w - > priv ;
2016-06-03 18:29:38 +05:30
if ( mconfig - > m_state > = SKL_MODULE_INIT_DONE )
skl_tplg_free_pipe_mcps ( skl , dst_module ) ;
2015-10-07 11:31:54 +01:00
if ( src_module = = NULL ) {
src_module = dst_module ;
continue ;
}
2016-02-03 17:59:46 +05:30
skl_unbind_modules ( ctx , src_module , dst_module ) ;
2015-10-07 11:31:54 +01:00
src_module = dst_module ;
}
ret = skl_delete_pipe ( ctx , mconfig - > pipe ) ;
2015-12-03 23:29:50 +05:30
return skl_tplg_unload_pipe_modules ( ctx , s_pipe ) ;
2015-10-07 11:31:54 +01:00
}
/*
* in the Post - PMD event of PGA we need to do following :
* - Free the mcps used
* - Stop the pipeline
* - In source pipe is connected , unbind with source pipelines
*/
static int skl_tplg_pga_dapm_post_pmd_event ( struct snd_soc_dapm_widget * w ,
struct skl * skl )
{
struct skl_module_cfg * src_mconfig , * sink_mconfig ;
2015-10-27 09:22:51 +09:00
int ret = 0 , i ;
2015-10-07 11:31:54 +01:00
struct skl_sst * ctx = skl - > skl_sst ;
2015-10-27 09:22:51 +09:00
src_mconfig = w - > priv ;
2015-10-07 11:31:54 +01:00
/* Stop the pipe since this is a mixin module */
ret = skl_stop_pipe ( ctx , src_mconfig - > pipe ) ;
if ( ret )
return ret ;
2015-10-27 09:22:51 +09:00
for ( i = 0 ; i < src_mconfig - > max_out_queue ; i + + ) {
if ( src_mconfig - > m_out_pin [ i ] . pin_state = = SKL_PIN_BIND_DONE ) {
sink_mconfig = src_mconfig - > m_out_pin [ i ] . tgt_mcfg ;
if ( ! sink_mconfig )
continue ;
/*
* This is a connecter and if path is found that means
* unbind between source and sink has not happened yet
*/
ret = skl_unbind_modules ( ctx , src_mconfig ,
sink_mconfig ) ;
2015-10-07 11:31:54 +01:00
}
}
return ret ;
}
/*
* In modelling , we assume there will be ONLY one mixer in a pipeline . If
* mixer is not required then it is treated as static mixer aka vmixer with
* a hard path to source module
* So we don ' t need to check if source is started or not as hard path puts
* dependency on each other
*/
static int skl_tplg_vmixer_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * k , int event )
{
struct snd_soc_dapm_context * dapm = w - > dapm ;
struct skl * skl = get_skl_ctx ( dapm - > dev ) ;
switch ( event ) {
case SND_SOC_DAPM_PRE_PMU :
return skl_tplg_mixer_dapm_pre_pmu_event ( w , skl ) ;
2016-02-03 17:59:52 +05:30
case SND_SOC_DAPM_POST_PMU :
return skl_tplg_mixer_dapm_post_pmu_event ( w , skl ) ;
case SND_SOC_DAPM_PRE_PMD :
return skl_tplg_mixer_dapm_pre_pmd_event ( w , skl ) ;
2015-10-07 11:31:54 +01:00
case SND_SOC_DAPM_POST_PMD :
return skl_tplg_mixer_dapm_post_pmd_event ( w , skl ) ;
}
return 0 ;
}
/*
* In modelling , we assume there will be ONLY one mixer in a pipeline . If a
* second one is required that is created as another pipe entity .
* The mixer is responsible for pipe management and represent a pipeline
* instance
*/
static int skl_tplg_mixer_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * k , int event )
{
struct snd_soc_dapm_context * dapm = w - > dapm ;
struct skl * skl = get_skl_ctx ( dapm - > dev ) ;
switch ( event ) {
case SND_SOC_DAPM_PRE_PMU :
return skl_tplg_mixer_dapm_pre_pmu_event ( w , skl ) ;
case SND_SOC_DAPM_POST_PMU :
return skl_tplg_mixer_dapm_post_pmu_event ( w , skl ) ;
case SND_SOC_DAPM_PRE_PMD :
return skl_tplg_mixer_dapm_pre_pmd_event ( w , skl ) ;
case SND_SOC_DAPM_POST_PMD :
return skl_tplg_mixer_dapm_post_pmd_event ( w , skl ) ;
}
return 0 ;
}
/*
* In modelling , we assumed rest of the modules in pipeline are PGA . But we
* are interested in last PGA ( leaf PGA ) in a pipeline to disconnect with
* the sink when it is running ( two FE to one BE or one FE to two BE )
* scenarios
*/
static int skl_tplg_pga_event ( struct snd_soc_dapm_widget * w ,
struct snd_kcontrol * k , int event )
{
struct snd_soc_dapm_context * dapm = w - > dapm ;
struct skl * skl = get_skl_ctx ( dapm - > dev ) ;
switch ( event ) {
case SND_SOC_DAPM_PRE_PMU :
return skl_tplg_pga_dapm_pre_pmu_event ( w , skl ) ;
case SND_SOC_DAPM_POST_PMD :
return skl_tplg_pga_dapm_post_pmd_event ( w , skl ) ;
}
return 0 ;
}
2015-10-07 11:31:55 +01:00
2015-11-28 15:01:50 +05:30
static int skl_tplg_tlv_control_get ( struct snd_kcontrol * kcontrol ,
unsigned int __user * data , unsigned int size )
{
struct soc_bytes_ext * sb =
( struct soc_bytes_ext * ) kcontrol - > private_value ;
struct skl_algo_data * bc = ( struct skl_algo_data * ) sb - > dobj . private ;
2015-12-03 23:29:56 +05:30
struct snd_soc_dapm_widget * w = snd_soc_dapm_kcontrol_widget ( kcontrol ) ;
struct skl_module_cfg * mconfig = w - > priv ;
struct skl * skl = get_skl_ctx ( w - > dapm - > dev ) ;
if ( w - > power )
skl_get_module_params ( skl - > skl_sst , ( u32 * ) bc - > params ,
bc - > max , bc - > param_id , mconfig ) ;
2015-11-28 15:01:50 +05:30
2016-02-03 17:59:44 +05:30
/* decrement size for TLV header */
size - = 2 * sizeof ( u32 ) ;
/* check size as we don't want to send kernel data */
if ( size > bc - > max )
size = bc - > max ;
2015-11-28 15:01:50 +05:30
if ( bc - > params ) {
if ( copy_to_user ( data , & bc - > param_id , sizeof ( u32 ) ) )
return - EFAULT ;
2015-12-08 08:53:22 +03:00
if ( copy_to_user ( data + 1 , & size , sizeof ( u32 ) ) )
2015-11-28 15:01:50 +05:30
return - EFAULT ;
2015-12-08 08:53:22 +03:00
if ( copy_to_user ( data + 2 , bc - > params , size ) )
2015-11-28 15:01:50 +05:30
return - EFAULT ;
}
return 0 ;
}
# define SKL_PARAM_VENDOR_ID 0xff
static int skl_tplg_tlv_control_set ( struct snd_kcontrol * kcontrol ,
const unsigned int __user * data , unsigned int size )
{
struct snd_soc_dapm_widget * w = snd_soc_dapm_kcontrol_widget ( kcontrol ) ;
struct skl_module_cfg * mconfig = w - > priv ;
struct soc_bytes_ext * sb =
( struct soc_bytes_ext * ) kcontrol - > private_value ;
struct skl_algo_data * ac = ( struct skl_algo_data * ) sb - > dobj . private ;
struct skl * skl = get_skl_ctx ( w - > dapm - > dev ) ;
if ( ac - > params ) {
/*
* if the param_is is of type Vendor , firmware expects actual
* parameter id and size from the control .
*/
if ( ac - > param_id = = SKL_PARAM_VENDOR_ID ) {
if ( copy_from_user ( ac - > params , data , size ) )
return - EFAULT ;
} else {
if ( copy_from_user ( ac - > params ,
2016-02-19 11:42:32 +05:30
data + 2 , size ) )
2015-11-28 15:01:50 +05:30
return - EFAULT ;
}
if ( w - > power )
return skl_set_module_params ( skl - > skl_sst ,
( u32 * ) ac - > params , ac - > max ,
ac - > param_id , mconfig ) ;
}
return 0 ;
}
2015-10-07 11:31:55 +01:00
/*
* The FE params are passed by hw_params of the DAI .
* On hw_params , the params are stored in Gateway module of the FE and we
* need to calculate the format in DSP module configuration , that
* conversion is done here
*/
int skl_tplg_update_pipe_params ( struct device * dev ,
struct skl_module_cfg * mconfig ,
struct skl_pipe_params * params )
{
struct skl_pipe * pipe = mconfig - > pipe ;
struct skl_module_fmt * format = NULL ;
memcpy ( pipe - > p_params , params , sizeof ( * params ) ) ;
if ( params - > stream = = SNDRV_PCM_STREAM_PLAYBACK )
2015-10-27 09:22:55 +09:00
format = & mconfig - > in_fmt [ 0 ] ;
2015-10-07 11:31:55 +01:00
else
2015-10-27 09:22:55 +09:00
format = & mconfig - > out_fmt [ 0 ] ;
2015-10-07 11:31:55 +01:00
/* set the hw_params */
format - > s_freq = params - > s_freq ;
format - > channels = params - > ch ;
format - > valid_bit_depth = skl_get_bit_depth ( params - > s_fmt ) ;
/*
* 16 bit is 16 bit container whereas 24 bit is in 32 bit
* container so update bit depth accordingly
*/
switch ( format - > valid_bit_depth ) {
case SKL_DEPTH_16BIT :
format - > bit_depth = format - > valid_bit_depth ;
break ;
case SKL_DEPTH_24BIT :
2015-10-27 09:22:46 +09:00
case SKL_DEPTH_32BIT :
2015-10-07 11:31:55 +01:00
format - > bit_depth = SKL_DEPTH_32BIT ;
break ;
default :
dev_err ( dev , " Invalid bit depth %x for pipe \n " ,
format - > valid_bit_depth ) ;
return - EINVAL ;
}
if ( params - > stream = = SNDRV_PCM_STREAM_PLAYBACK ) {
mconfig - > ibs = ( format - > s_freq / 1000 ) *
( format - > channels ) *
( format - > bit_depth > > 3 ) ;
} else {
mconfig - > obs = ( format - > s_freq / 1000 ) *
( format - > channels ) *
( format - > bit_depth > > 3 ) ;
}
return 0 ;
}
/*
* Query the module config for the FE DAI
* This is used to find the hw_params set for that DAI and apply to FE
* pipeline
*/
struct skl_module_cfg *
skl_tplg_fe_get_cpr_module ( struct snd_soc_dai * dai , int stream )
{
struct snd_soc_dapm_widget * w ;
struct snd_soc_dapm_path * p = NULL ;
if ( stream = = SNDRV_PCM_STREAM_PLAYBACK ) {
w = dai - > playback_widget ;
2015-10-22 23:22:36 +05:30
snd_soc_dapm_widget_for_each_sink_path ( w , p ) {
2015-10-07 11:31:55 +01:00
if ( p - > connect & & p - > sink - > power & &
2015-10-27 09:22:44 +09:00
! is_skl_dsp_widget_type ( p - > sink ) )
2015-10-07 11:31:55 +01:00
continue ;
if ( p - > sink - > priv ) {
dev_dbg ( dai - > dev , " set params for %s \n " ,
p - > sink - > name ) ;
return p - > sink - > priv ;
}
}
} else {
w = dai - > capture_widget ;
2015-10-22 23:22:36 +05:30
snd_soc_dapm_widget_for_each_source_path ( w , p ) {
2015-10-07 11:31:55 +01:00
if ( p - > connect & & p - > source - > power & &
2015-10-27 09:22:44 +09:00
! is_skl_dsp_widget_type ( p - > source ) )
2015-10-07 11:31:55 +01:00
continue ;
if ( p - > source - > priv ) {
dev_dbg ( dai - > dev , " set params for %s \n " ,
p - > source - > name ) ;
return p - > source - > priv ;
}
}
}
return NULL ;
}
2016-02-05 12:19:06 +05:30
static struct skl_module_cfg * skl_get_mconfig_pb_cpr (
struct snd_soc_dai * dai , struct snd_soc_dapm_widget * w )
{
struct snd_soc_dapm_path * p ;
struct skl_module_cfg * mconfig = NULL ;
snd_soc_dapm_widget_for_each_source_path ( w , p ) {
if ( w - > endpoints [ SND_SOC_DAPM_DIR_OUT ] > 0 ) {
if ( p - > connect & &
( p - > sink - > id = = snd_soc_dapm_aif_out ) & &
p - > source - > priv ) {
mconfig = p - > source - > priv ;
return mconfig ;
}
mconfig = skl_get_mconfig_pb_cpr ( dai , p - > source ) ;
if ( mconfig )
return mconfig ;
}
}
return mconfig ;
}
static struct skl_module_cfg * skl_get_mconfig_cap_cpr (
struct snd_soc_dai * dai , struct snd_soc_dapm_widget * w )
{
struct snd_soc_dapm_path * p ;
struct skl_module_cfg * mconfig = NULL ;
snd_soc_dapm_widget_for_each_sink_path ( w , p ) {
if ( w - > endpoints [ SND_SOC_DAPM_DIR_IN ] > 0 ) {
if ( p - > connect & &
( p - > source - > id = = snd_soc_dapm_aif_in ) & &
p - > sink - > priv ) {
mconfig = p - > sink - > priv ;
return mconfig ;
}
mconfig = skl_get_mconfig_cap_cpr ( dai , p - > sink ) ;
if ( mconfig )
return mconfig ;
}
}
return mconfig ;
}
struct skl_module_cfg *
skl_tplg_be_get_cpr_module ( struct snd_soc_dai * dai , int stream )
{
struct snd_soc_dapm_widget * w ;
struct skl_module_cfg * mconfig ;
if ( stream = = SNDRV_PCM_STREAM_PLAYBACK ) {
w = dai - > playback_widget ;
mconfig = skl_get_mconfig_pb_cpr ( dai , w ) ;
} else {
w = dai - > capture_widget ;
mconfig = skl_get_mconfig_cap_cpr ( dai , w ) ;
}
return mconfig ;
}
2015-10-07 11:31:55 +01:00
static u8 skl_tplg_be_link_type ( int dev_type )
{
int ret ;
switch ( dev_type ) {
case SKL_DEVICE_BT :
ret = NHLT_LINK_SSP ;
break ;
case SKL_DEVICE_DMIC :
ret = NHLT_LINK_DMIC ;
break ;
case SKL_DEVICE_I2S :
ret = NHLT_LINK_SSP ;
break ;
case SKL_DEVICE_HDALINK :
ret = NHLT_LINK_HDA ;
break ;
default :
ret = NHLT_LINK_INVALID ;
break ;
}
return ret ;
}
/*
* Fill the BE gateway parameters
* The BE gateway expects a blob of parameters which are kept in the ACPI
* NHLT blob , so query the blob for interface type ( i2s / pdm ) and instance .
* The port can have multiple settings so pick based on the PCM
* parameters
*/
static int skl_tplg_be_fill_pipe_params ( struct snd_soc_dai * dai ,
struct skl_module_cfg * mconfig ,
struct skl_pipe_params * params )
{
struct skl_pipe * pipe = mconfig - > pipe ;
struct nhlt_specific_cfg * cfg ;
struct skl * skl = get_skl_ctx ( dai - > dev ) ;
int link_type = skl_tplg_be_link_type ( mconfig - > dev_type ) ;
memcpy ( pipe - > p_params , params , sizeof ( * params ) ) ;
2015-10-27 09:22:48 +09:00
if ( link_type = = NHLT_LINK_HDA )
return 0 ;
2015-10-07 11:31:55 +01:00
/* update the blob based on virtual bus_id*/
cfg = skl_get_ep_blob ( skl , mconfig - > vbus_id , link_type ,
params - > s_fmt , params - > ch ,
params - > s_freq , params - > stream ) ;
if ( cfg ) {
mconfig - > formats_config . caps_size = cfg - > size ;
2015-10-22 23:22:35 +05:30
mconfig - > formats_config . caps = ( u32 * ) & cfg - > caps ;
2015-10-07 11:31:55 +01:00
} else {
dev_err ( dai - > dev , " Blob NULL for id %x type %d dirn %d \n " ,
mconfig - > vbus_id , link_type ,
params - > stream ) ;
dev_err ( dai - > dev , " PCM: ch %d, freq %d, fmt %d \n " ,
params - > ch , params - > s_freq , params - > s_fmt ) ;
return - EINVAL ;
}
return 0 ;
}
static int skl_tplg_be_set_src_pipe_params ( struct snd_soc_dai * dai ,
struct snd_soc_dapm_widget * w ,
struct skl_pipe_params * params )
{
struct snd_soc_dapm_path * p ;
2015-10-22 23:22:37 +05:30
int ret = - EIO ;
2015-10-07 11:31:55 +01:00
2015-10-22 23:22:36 +05:30
snd_soc_dapm_widget_for_each_source_path ( w , p ) {
2015-10-07 11:31:55 +01:00
if ( p - > connect & & is_skl_dsp_widget_type ( p - > source ) & &
p - > source - > priv ) {
2015-10-27 09:22:54 +09:00
ret = skl_tplg_be_fill_pipe_params ( dai ,
p - > source - > priv , params ) ;
if ( ret < 0 )
return ret ;
2015-10-07 11:31:55 +01:00
} else {
2015-10-27 09:22:54 +09:00
ret = skl_tplg_be_set_src_pipe_params ( dai ,
p - > source , params ) ;
2015-10-22 23:22:37 +05:30
if ( ret < 0 )
return ret ;
2015-10-07 11:31:55 +01:00
}
}
2015-10-22 23:22:37 +05:30
return ret ;
2015-10-07 11:31:55 +01:00
}
static int skl_tplg_be_set_sink_pipe_params ( struct snd_soc_dai * dai ,
struct snd_soc_dapm_widget * w , struct skl_pipe_params * params )
{
struct snd_soc_dapm_path * p = NULL ;
2015-10-22 23:22:37 +05:30
int ret = - EIO ;
2015-10-07 11:31:55 +01:00
2015-10-22 23:22:36 +05:30
snd_soc_dapm_widget_for_each_sink_path ( w , p ) {
2015-10-07 11:31:55 +01:00
if ( p - > connect & & is_skl_dsp_widget_type ( p - > sink ) & &
p - > sink - > priv ) {
2015-10-27 09:22:54 +09:00
ret = skl_tplg_be_fill_pipe_params ( dai ,
p - > sink - > priv , params ) ;
if ( ret < 0 )
return ret ;
2015-10-07 11:31:55 +01:00
} else {
2015-10-22 23:22:37 +05:30
ret = skl_tplg_be_set_sink_pipe_params (
2015-10-07 11:31:55 +01:00
dai , p - > sink , params ) ;
2015-10-22 23:22:37 +05:30
if ( ret < 0 )
return ret ;
2015-10-07 11:31:55 +01:00
}
}
2015-10-22 23:22:37 +05:30
return ret ;
2015-10-07 11:31:55 +01:00
}
/*
* BE hw_params can be a source parameters ( capture ) or sink parameters
* ( playback ) . Based on sink and source we need to either find the source
* list or the sink list and set the pipeline parameters
*/
int skl_tplg_be_update_params ( struct snd_soc_dai * dai ,
struct skl_pipe_params * params )
{
struct snd_soc_dapm_widget * w ;
if ( params - > stream = = SNDRV_PCM_STREAM_PLAYBACK ) {
w = dai - > playback_widget ;
return skl_tplg_be_set_src_pipe_params ( dai , w , params ) ;
} else {
w = dai - > capture_widget ;
return skl_tplg_be_set_sink_pipe_params ( dai , w , params ) ;
}
return 0 ;
}
2015-10-07 11:31:56 +01:00
static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops [ ] = {
{ SKL_MIXER_EVENT , skl_tplg_mixer_event } ,
{ SKL_VMIXER_EVENT , skl_tplg_vmixer_event } ,
{ SKL_PGA_EVENT , skl_tplg_pga_event } ,
} ;
2015-11-28 15:01:50 +05:30
static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops [ ] = {
{ SKL_CONTROL_TYPE_BYTE_TLV , skl_tplg_tlv_control_get ,
skl_tplg_tlv_control_set } ,
} ;
2015-10-07 11:31:56 +01:00
/*
* The topology binary passes the pin info for a module so initialize the pin
* info passed into module instance
*/
2015-10-22 23:22:42 +05:30
static void skl_fill_module_pin_info ( struct skl_dfw_module_pin * dfw_pin ,
struct skl_module_pin * m_pin ,
bool is_dynamic , int max_pin )
2015-10-07 11:31:56 +01:00
{
int i ;
for ( i = 0 ; i < max_pin ; i + + ) {
2015-10-22 23:22:42 +05:30
m_pin [ i ] . id . module_id = dfw_pin [ i ] . module_id ;
m_pin [ i ] . id . instance_id = dfw_pin [ i ] . instance_id ;
2015-10-07 11:31:56 +01:00
m_pin [ i ] . in_use = false ;
2015-10-22 23:22:42 +05:30
m_pin [ i ] . is_dynamic = is_dynamic ;
2015-10-27 09:22:49 +09:00
m_pin [ i ] . pin_state = SKL_PIN_UNBIND ;
2015-10-07 11:31:56 +01:00
}
}
/*
* Add pipeline from topology binary into driver pipeline list
*
* If already added we return that instance
* Otherwise we create a new instance and add into driver list
*/
static struct skl_pipe * skl_tplg_add_pipe ( struct device * dev ,
struct skl * skl , struct skl_dfw_pipe * dfw_pipe )
{
struct skl_pipeline * ppl ;
struct skl_pipe * pipe ;
struct skl_pipe_params * params ;
list_for_each_entry ( ppl , & skl - > ppl_list , node ) {
if ( ppl - > pipe - > ppl_id = = dfw_pipe - > pipe_id )
return ppl - > pipe ;
}
ppl = devm_kzalloc ( dev , sizeof ( * ppl ) , GFP_KERNEL ) ;
if ( ! ppl )
return NULL ;
pipe = devm_kzalloc ( dev , sizeof ( * pipe ) , GFP_KERNEL ) ;
if ( ! pipe )
return NULL ;
params = devm_kzalloc ( dev , sizeof ( * params ) , GFP_KERNEL ) ;
if ( ! params )
return NULL ;
pipe - > ppl_id = dfw_pipe - > pipe_id ;
pipe - > memory_pages = dfw_pipe - > memory_pages ;
pipe - > pipe_priority = dfw_pipe - > pipe_priority ;
pipe - > conn_type = dfw_pipe - > conn_type ;
pipe - > state = SKL_PIPE_INVALID ;
pipe - > p_params = params ;
INIT_LIST_HEAD ( & pipe - > w_list ) ;
ppl - > pipe = pipe ;
list_add ( & ppl - > node , & skl - > ppl_list ) ;
return ppl - > pipe ;
}
2015-10-27 09:22:55 +09:00
static void skl_tplg_fill_fmt ( struct skl_module_fmt * dst_fmt ,
struct skl_dfw_module_fmt * src_fmt ,
int pins )
{
int i ;
for ( i = 0 ; i < pins ; i + + ) {
dst_fmt [ i ] . channels = src_fmt [ i ] . channels ;
dst_fmt [ i ] . s_freq = src_fmt [ i ] . freq ;
dst_fmt [ i ] . bit_depth = src_fmt [ i ] . bit_depth ;
dst_fmt [ i ] . valid_bit_depth = src_fmt [ i ] . valid_bit_depth ;
dst_fmt [ i ] . ch_cfg = src_fmt [ i ] . ch_cfg ;
dst_fmt [ i ] . ch_map = src_fmt [ i ] . ch_map ;
dst_fmt [ i ] . interleaving_style = src_fmt [ i ] . interleaving_style ;
dst_fmt [ i ] . sample_type = src_fmt [ i ] . sample_type ;
}
}
2016-06-03 18:29:39 +05:30
static void skl_clear_pin_config ( struct snd_soc_platform * platform ,
struct snd_soc_dapm_widget * w )
{
int i ;
struct skl_module_cfg * mconfig ;
struct skl_pipe * pipe ;
if ( ! strncmp ( w - > dapm - > component - > name , platform - > component . name ,
strlen ( platform - > component . name ) ) ) {
mconfig = w - > priv ;
pipe = mconfig - > pipe ;
for ( i = 0 ; i < mconfig - > max_in_queue ; i + + ) {
mconfig - > m_in_pin [ i ] . in_use = false ;
mconfig - > m_in_pin [ i ] . pin_state = SKL_PIN_UNBIND ;
}
for ( i = 0 ; i < mconfig - > max_out_queue ; i + + ) {
mconfig - > m_out_pin [ i ] . in_use = false ;
mconfig - > m_out_pin [ i ] . pin_state = SKL_PIN_UNBIND ;
}
pipe - > state = SKL_PIPE_INVALID ;
mconfig - > m_state = SKL_MODULE_UNINIT ;
}
}
void skl_cleanup_resources ( struct skl * skl )
{
struct skl_sst * ctx = skl - > skl_sst ;
struct snd_soc_platform * soc_platform = skl - > platform ;
struct snd_soc_dapm_widget * w ;
struct snd_soc_card * card ;
if ( soc_platform = = NULL )
return ;
card = soc_platform - > component . card ;
if ( ! card | | ! card - > instantiated )
return ;
skl - > resource . mem = 0 ;
skl - > resource . mcps = 0 ;
list_for_each_entry ( w , & card - > widgets , list ) {
if ( is_skl_dsp_widget_type ( w ) & & ( w - > priv ! = NULL ) )
skl_clear_pin_config ( soc_platform , w ) ;
}
skl_clear_module_cnt ( ctx - > dsp ) ;
}
2015-10-07 11:31:56 +01:00
/*
* Topology core widget load callback
*
* This is used to save the private data for each widget which gives
* information to the driver about module and pipeline parameters which DSP
* FW expects like ids , resource values , formats etc
*/
static int skl_tplg_widget_load ( struct snd_soc_component * cmpnt ,
2015-10-07 11:31:57 +01:00
struct snd_soc_dapm_widget * w ,
struct snd_soc_tplg_dapm_widget * tplg_w )
2015-10-07 11:31:56 +01:00
{
int ret ;
struct hdac_ext_bus * ebus = snd_soc_component_get_drvdata ( cmpnt ) ;
struct skl * skl = ebus_to_skl ( ebus ) ;
struct hdac_bus * bus = ebus_to_hbus ( ebus ) ;
struct skl_module_cfg * mconfig ;
struct skl_pipe * pipe ;
2015-10-07 11:31:57 +01:00
struct skl_dfw_module * dfw_config =
( struct skl_dfw_module * ) tplg_w - > priv . data ;
2015-10-07 11:31:56 +01:00
if ( ! tplg_w - > priv . size )
goto bind_event ;
mconfig = devm_kzalloc ( bus - > dev , sizeof ( * mconfig ) , GFP_KERNEL ) ;
if ( ! mconfig )
return - ENOMEM ;
w - > priv = mconfig ;
2016-04-21 11:45:22 +05:30
memcpy ( & mconfig - > guid , & dfw_config - > uuid , 16 ) ;
2016-05-30 17:42:59 +05:30
ret = snd_skl_get_module_info ( skl - > skl_sst , mconfig - > guid , dfw_config ) ;
if ( ret < 0 )
return ret ;
2015-10-07 11:31:56 +01:00
mconfig - > id . module_id = dfw_config - > module_id ;
mconfig - > id . instance_id = dfw_config - > instance_id ;
mconfig - > mcps = dfw_config - > max_mcps ;
mconfig - > ibs = dfw_config - > ibs ;
mconfig - > obs = dfw_config - > obs ;
mconfig - > core_id = dfw_config - > core_id ;
mconfig - > max_in_queue = dfw_config - > max_in_queue ;
mconfig - > max_out_queue = dfw_config - > max_out_queue ;
mconfig - > is_loadable = dfw_config - > is_loadable ;
2015-10-27 09:22:55 +09:00
skl_tplg_fill_fmt ( mconfig - > in_fmt , dfw_config - > in_fmt ,
MODULE_MAX_IN_PINS ) ;
skl_tplg_fill_fmt ( mconfig - > out_fmt , dfw_config - > out_fmt ,
MODULE_MAX_OUT_PINS ) ;
2015-10-07 11:31:56 +01:00
mconfig - > params_fixup = dfw_config - > params_fixup ;
mconfig - > converter = dfw_config - > converter ;
mconfig - > m_type = dfw_config - > module_type ;
mconfig - > vbus_id = dfw_config - > vbus_id ;
2015-12-03 23:29:51 +05:30
mconfig - > mem_pages = dfw_config - > mem_pages ;
2015-10-07 11:31:56 +01:00
pipe = skl_tplg_add_pipe ( bus - > dev , skl , & dfw_config - > pipe ) ;
if ( pipe )
mconfig - > pipe = pipe ;
mconfig - > dev_type = dfw_config - > dev_type ;
mconfig - > hw_conn_type = dfw_config - > hw_conn_type ;
mconfig - > time_slot = dfw_config - > time_slot ;
mconfig - > formats_config . caps_size = dfw_config - > caps . caps_size ;
2015-10-27 09:22:55 +09:00
mconfig - > m_in_pin = devm_kzalloc ( bus - > dev , ( mconfig - > max_in_queue ) *
sizeof ( * mconfig - > m_in_pin ) ,
GFP_KERNEL ) ;
2015-10-07 11:31:56 +01:00
if ( ! mconfig - > m_in_pin )
return - ENOMEM ;
2015-10-22 23:22:42 +05:30
mconfig - > m_out_pin = devm_kzalloc ( bus - > dev , ( mconfig - > max_out_queue ) *
sizeof ( * mconfig - > m_out_pin ) ,
GFP_KERNEL ) ;
2015-10-07 11:31:56 +01:00
if ( ! mconfig - > m_out_pin )
return - ENOMEM ;
2015-10-22 23:22:42 +05:30
skl_fill_module_pin_info ( dfw_config - > in_pin , mconfig - > m_in_pin ,
dfw_config - > is_dynamic_in_pin ,
mconfig - > max_in_queue ) ;
skl_fill_module_pin_info ( dfw_config - > out_pin , mconfig - > m_out_pin ,
dfw_config - > is_dynamic_out_pin ,
mconfig - > max_out_queue ) ;
2015-10-07 11:31:56 +01:00
if ( mconfig - > formats_config . caps_size = = 0 )
goto bind_event ;
mconfig - > formats_config . caps = ( u32 * ) devm_kzalloc ( bus - > dev ,
2015-10-07 11:31:57 +01:00
mconfig - > formats_config . caps_size , GFP_KERNEL ) ;
2015-10-07 11:31:56 +01:00
if ( mconfig - > formats_config . caps = = NULL )
return - ENOMEM ;
memcpy ( mconfig - > formats_config . caps , dfw_config - > caps . caps ,
2015-11-28 15:01:49 +05:30
dfw_config - > caps . caps_size ) ;
mconfig - > formats_config . param_id = dfw_config - > caps . param_id ;
mconfig - > formats_config . set_params = dfw_config - > caps . set_params ;
2015-10-07 11:31:56 +01:00
bind_event :
if ( tplg_w - > event_type = = 0 ) {
2015-10-07 16:39:38 +01:00
dev_dbg ( bus - > dev , " ASoC: No event handler required \n " ) ;
2015-10-07 11:31:56 +01:00
return 0 ;
}
ret = snd_soc_tplg_widget_bind_event ( w , skl_tplg_widget_ops ,
2015-10-07 11:31:57 +01:00
ARRAY_SIZE ( skl_tplg_widget_ops ) ,
tplg_w - > event_type ) ;
2015-10-07 11:31:56 +01:00
if ( ret ) {
dev_err ( bus - > dev , " %s: No matching event handlers found for %d \n " ,
__func__ , tplg_w - > event_type ) ;
return - EINVAL ;
}
return 0 ;
}
2015-11-28 15:01:50 +05:30
static int skl_init_algo_data ( struct device * dev , struct soc_bytes_ext * be ,
struct snd_soc_tplg_bytes_control * bc )
{
struct skl_algo_data * ac ;
struct skl_dfw_algo_data * dfw_ac =
( struct skl_dfw_algo_data * ) bc - > priv . data ;
ac = devm_kzalloc ( dev , sizeof ( * ac ) , GFP_KERNEL ) ;
if ( ! ac )
return - ENOMEM ;
/* Fill private data */
ac - > max = dfw_ac - > max ;
ac - > param_id = dfw_ac - > param_id ;
ac - > set_params = dfw_ac - > set_params ;
if ( ac - > max ) {
ac - > params = ( char * ) devm_kzalloc ( dev , ac - > max , GFP_KERNEL ) ;
if ( ! ac - > params )
return - ENOMEM ;
2016-02-22 09:37:27 +05:30
memcpy ( ac - > params , dfw_ac - > params , ac - > max ) ;
2015-11-28 15:01:50 +05:30
}
be - > dobj . private = ac ;
return 0 ;
}
static int skl_tplg_control_load ( struct snd_soc_component * cmpnt ,
struct snd_kcontrol_new * kctl ,
struct snd_soc_tplg_ctl_hdr * hdr )
{
struct soc_bytes_ext * sb ;
struct snd_soc_tplg_bytes_control * tplg_bc ;
struct hdac_ext_bus * ebus = snd_soc_component_get_drvdata ( cmpnt ) ;
struct hdac_bus * bus = ebus_to_hbus ( ebus ) ;
switch ( hdr - > ops . info ) {
case SND_SOC_TPLG_CTL_BYTES :
tplg_bc = container_of ( hdr ,
struct snd_soc_tplg_bytes_control , hdr ) ;
if ( kctl - > access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK ) {
sb = ( struct soc_bytes_ext * ) kctl - > private_value ;
if ( tplg_bc - > priv . size )
return skl_init_algo_data (
bus - > dev , sb , tplg_bc ) ;
}
break ;
default :
dev_warn ( bus - > dev , " Control load not supported %d:%d:%d \n " ,
hdr - > ops . get , hdr - > ops . put , hdr - > ops . info ) ;
break ;
}
return 0 ;
}
2015-10-07 11:31:56 +01:00
static struct snd_soc_tplg_ops skl_tplg_ops = {
. widget_load = skl_tplg_widget_load ,
2015-11-28 15:01:50 +05:30
. control_load = skl_tplg_control_load ,
. bytes_ext_ops = skl_tlv_ops ,
. bytes_ext_ops_count = ARRAY_SIZE ( skl_tlv_ops ) ,
2015-10-07 11:31:56 +01:00
} ;
2016-06-03 18:29:40 +05:30
/*
* A pipe can have multiple modules , each of them will be a DAPM widget as
* well . While managing a pipeline we need to get the list of all the
* widgets in a pipelines , so this helper - skl_tplg_create_pipe_widget_list ( )
* helps to get the SKL type widgets in that pipeline
*/
static int skl_tplg_create_pipe_widget_list ( struct snd_soc_platform * platform )
{
struct snd_soc_dapm_widget * w ;
struct skl_module_cfg * mcfg = NULL ;
struct skl_pipe_module * p_module = NULL ;
struct skl_pipe * pipe ;
list_for_each_entry ( w , & platform - > component . card - > widgets , list ) {
if ( is_skl_dsp_widget_type ( w ) & & w - > priv ! = NULL ) {
mcfg = w - > priv ;
pipe = mcfg - > pipe ;
p_module = devm_kzalloc ( platform - > dev ,
sizeof ( * p_module ) , GFP_KERNEL ) ;
if ( ! p_module )
return - ENOMEM ;
p_module - > w = w ;
list_add_tail ( & p_module - > node , & pipe - > w_list ) ;
}
}
return 0 ;
}
2016-06-03 18:29:41 +05:30
static void skl_tplg_set_pipe_type ( struct skl * skl , struct skl_pipe * pipe )
{
struct skl_pipe_module * w_module ;
struct snd_soc_dapm_widget * w ;
struct skl_module_cfg * mconfig ;
bool host_found = false , link_found = false ;
list_for_each_entry ( w_module , & pipe - > w_list , node ) {
w = w_module - > w ;
mconfig = w - > priv ;
if ( mconfig - > dev_type = = SKL_DEVICE_HDAHOST )
host_found = true ;
else if ( mconfig - > dev_type ! = SKL_DEVICE_NONE )
link_found = true ;
}
if ( host_found & & link_found )
pipe - > passthru = true ;
else
pipe - > passthru = false ;
}
2015-10-07 11:31:56 +01:00
/* This will be read from topology manifest, currently defined here */
# define SKL_MAX_MCPS 30000000
# define SKL_FW_MAX_MEM 1000000
/*
* SKL topology init routine
*/
int skl_tplg_init ( struct snd_soc_platform * platform , struct hdac_ext_bus * ebus )
{
int ret ;
const struct firmware * fw ;
struct hdac_bus * bus = ebus_to_hbus ( ebus ) ;
struct skl * skl = ebus_to_skl ( ebus ) ;
2016-06-03 18:29:41 +05:30
struct skl_pipeline * ppl ;
2015-10-07 11:31:56 +01:00
2016-02-19 11:42:34 +05:30
ret = request_firmware ( & fw , skl - > tplg_name , bus - > dev ) ;
2015-10-07 11:31:56 +01:00
if ( ret < 0 ) {
2015-10-07 11:31:57 +01:00
dev_err ( bus - > dev , " tplg fw %s load failed with %d \n " ,
2016-02-19 11:42:34 +05:30
skl - > tplg_name , ret ) ;
ret = request_firmware ( & fw , " dfw_sst.bin " , bus - > dev ) ;
if ( ret < 0 ) {
dev_err ( bus - > dev , " Fallback tplg fw %s load failed with %d \n " ,
" dfw_sst.bin " , ret ) ;
return ret ;
}
2015-10-07 11:31:56 +01:00
}
/*
* The complete tplg for SKL is loaded as index 0 , we don ' t use
* any other index
*/
2015-10-07 11:31:57 +01:00
ret = snd_soc_tplg_component_load ( & platform - > component ,
& skl_tplg_ops , fw , 0 ) ;
2015-10-07 11:31:56 +01:00
if ( ret < 0 ) {
dev_err ( bus - > dev , " tplg component load failed%d \n " , ret ) ;
2016-01-21 17:27:59 +05:30
release_firmware ( fw ) ;
2015-10-07 11:31:56 +01:00
return - EINVAL ;
}
skl - > resource . max_mcps = SKL_MAX_MCPS ;
skl - > resource . max_mem = SKL_FW_MAX_MEM ;
2016-01-05 17:16:04 +05:30
skl - > tplg = fw ;
2016-06-03 18:29:40 +05:30
ret = skl_tplg_create_pipe_widget_list ( platform ) ;
if ( ret < 0 )
return ret ;
2016-01-05 17:16:04 +05:30
2016-06-03 18:29:41 +05:30
list_for_each_entry ( ppl , & skl - > ppl_list , node )
skl_tplg_set_pipe_type ( skl , ppl - > pipe ) ;
2015-10-07 11:31:56 +01:00
return 0 ;
}