ASoC: Intel: add function to load firmware image
Subsystems (3)
PATCH 1/8 ASoC: Intel: add function to load firmware image
From: "Lu, Han" <[email protected]>
Add a general method to load firmware image, and apply to base firmware image loading. With the method, the driver will support loading multiple different modules in order to support different features.
sound/soc/intel/sst-dsp-priv.h +13 -0
@@ -173,6 +173,16 @@ struct sst_module_runtime_context { };/* +* Audio DSP Module State +*/ +enum sst_module_state { +SST_MODULE_STATE_UNLOADED =0 ,/* default state */ +SST_MODULE_STATE_LOADED , +SST_MODULE_STATE_INITIALIZED ,/* and inactive */ +SST_MODULE_STATE_ACTIVE , +}; + +/* * Audio DSP Generic Module. * * Each Firmware file can consist of 1..N modules. A module can span multiple
@@ -203,6 +213,9 @@ struct sst_module {struct list_head list;/* DSP list of modules */ struct list_head list_fw;/* FW list of modules */ struct list_head runtime_list;/* list of runtime module objects*/ + +/* state */ +enum sst_module_state state; };/*
sound/soc/intel/sst-firmware.c +1 -0
@@ -498,6 +498,7 @@ struct sst_module *sst_module_new(struct sst_fw *sst_fw, sst_module->scratch_size = template->scratch_size; sst_module->persistent_size = template->persistent_size; sst_module->entry = template->entry; + sst_module->state =SST_MODULE_STATE_UNLOADED ;INIT_LIST_HEAD (&sst_module->block_list);INIT_LIST_HEAD (&sst_module->runtime_list);
sound/soc/intel/sst-haswell-dsp.c +1 -0
@@ -169,6 +169,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, block = (void *)block +sizeof (*block) + block->size; } + mod->state =SST_MODULE_STATE_LOADED ;return 0 ; }
sound/soc/intel/sst-haswell-ipc.c +78 -6
115 lines not on this page · raw message
sound/soc/intel/sst-haswell-ipc.h +6 -0
@@ -467,6 +467,12 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata);void sst_hsw_dsp_free (struct device *dev,struct sst_pdata *pdata);struct sst_dsp *sst_hsw_get_dsp (struct sst_hsw *hsw); +/* fw module function */ +void sst_hsw_init_module_state (struct sst_hsw *hsw); + +int sst_hsw_module_load (struct sst_hsw *hsw, +u32 module_id,u32 instance_id,char *name); +/* runtime module management */ struct sst_module_runtime *sst_hsw_runtime_module_create (struct sst_hsw *hsw,int mod_id,int offset);
Signature · 1 line
1.9.1
PATCH 2/8 ASoC: Intel: add function to load sound effect module waves
From: "Lu, Han" <[email protected]>
Try to load module waves and allocate runtime blocks for it if the firmware image of module waves exists.
sound/soc/intel/sst-haswell-dsp.c +2 -0
@@ -100,6 +100,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, && module->type !=SST_HSW_MODULE_PCM && module->type !=SST_HSW_MODULE_PCM_REFERENCE && module->type !=SST_HSW_MODULE_PCM_CAPTURE + && module->type !=SST_HSW_MODULE_WAVES && module->type != SST_HSW_MODULE_LPAL) return 0;
@@ -139,6 +140,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, mod->type =SST_MEM_IRAM ;break ;case SST_HSW_DRAM : +case SST_HSW_REGS : ram = dsp->addr.lpe; mod->offset = block->ram_offset; mod->type =SST_MEM_DRAM ;
sound/soc/intel/sst-haswell-ipc.c +21 -2
@@ -1896,11 +1896,27 @@ void sst_hsw_init_module_state(struct sst_hsw *hsw)/* the base fw contains several modules */ for (id =SST_HSW_MODULE_BASE_FW ; id <SST_HSW_MAX_MODULE_ID ; id++) { module =sst_module_get_from_id (hsw->dsp, id); -if (module) - module->state =SST_MODULE_STATE_ACTIVE ; +if (module) { +/* module waves is active only after being enabled */ +if (id ==SST_HSW_MODULE_WAVES ) + module->state =SST_MODULE_STATE_INITIALIZED ; +else + module->state =SST_MODULE_STATE_ACTIVE ; + } } } +bool sst_hsw_is_module_loaded (struct sst_hsw *hsw,u32 module_id) +{ +struct sst_module *module; + + module =sst_module_get_from_id (hsw->dsp, module_id); +if (module ==NULL || module->state ==SST_MODULE_STATE_UNLOADED ) +return false; +else +return true; +} +int sst_hsw_module_load (struct sst_hsw *hsw,u32 module_id,u32 instance_id,char *name) {
@@ -2023,6 +2039,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)if (ret <0 ) goto fw_err; +/* try to load module waves */ +sst_hsw_module_load (hsw,SST_HSW_MODULE_WAVES ,0 ,"intel/IntcPP01.bin" ); +/* allocate scratch mem regions */ ret =sst_block_alloc_scratch (hsw->dsp);if (ret <0 )
sound/soc/intel/sst-haswell-ipc.h +1 -0
@@ -469,6 +469,7 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw);/* fw module function */ void sst_hsw_init_module_state (struct sst_hsw *hsw); +bool sst_hsw_is_module_loaded (struct sst_hsw *hsw,u32 module_id);int sst_hsw_module_load (struct sst_hsw *hsw,u32 module_id,u32 instance_id,char *name);
sound/soc/intel/sst-haswell-pcm.c +19 -2
@@ -807,6 +807,17 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) pcm_data->runtime->persistent_offset; } +/* create runtime blocks for module waves */ +if (sst_hsw_is_module_loaded (hsw,SST_HSW_MODULE_WAVES )) { + pcm_data = &pdata->pcm[HSW_PCM_COUNT -1 ][0 ]; + pcm_data->runtime =sst_hsw_runtime_module_create (hsw, +SST_HSW_MODULE_WAVES , pcm_data->persistent_offset); +if (pcm_data->runtime ==NULL ) + goto err; + pcm_data->persistent_offset = + pcm_data->runtime->persistent_offset; + } +return 0 ; err:
@@ -820,12 +831,16 @@ err:static void hsw_pcm_free_modules (struct hsw_priv_data *pdata) { +struct sst_hsw *hsw = pdata->hsw;struct hsw_pcm_data *pcm_data;int i;for (i =0 ; i <ARRAY_SIZE (mod_map); i++) { pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; - +sst_hsw_runtime_module_free (pcm_data->runtime); + } +if (sst_hsw_is_module_loaded (hsw,SST_HSW_MODULE_WAVES )) { + pcm_data = &pdata->pcm[HSW_PCM_COUNT -1 ][0 ];sst_hsw_runtime_module_free (pcm_data->runtime); } }
@@ -984,7 +999,9 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) }/* allocate runtime modules */ -hsw_pcm_create_modules (priv_data); + ret =hsw_pcm_create_modules (priv_data); +if (ret <0 ) + goto err;/* enable runtime PM with auto suspend */ pm_runtime_set_autosuspend_delay(platform->dev,
Signature · 1 line
1.9.1
PATCH 3/8 ASoC: Intel: add function to enable/disable sound effect module waves
In reply to [email protected]From: "Lu, Han" <[email protected]>
sound/soc/intel/sst-haswell-ipc.c +178 -0
@@ -79,6 +79,15 @@#define IPC_LOG_ID_MASK (0xf << IPC_LOG_ID_SHIFT)#define IPC_LOG_ID (x) (x << IPC_LOG_ID_SHIFT) +/* Module Message */ +#define IPC_MODULE_OPERATION_SHIFT 20 +#define IPC_MODULE_OPERATION_MASK (0xf << IPC_MODULE_OPERATION_SHIFT) +#define IPC_MODULE_OPERATION (x) (x << IPC_MODULE_OPERATION_SHIFT) + +#define IPC_MODULE_ID_SHIFT 16 +#define IPC_MODULE_ID_MASK (0xf << IPC_MODULE_ID_SHIFT) +#define IPC_MODULE_ID (x) (x << IPC_MODULE_ID_SHIFT) +/* IPC message timeout (msecs) */ #define IPC_TIMEOUT_MSECS 300#define IPC_BOOT_MSECS 200
@@ -115,6 +124,7 @@ enum ipc_glb_type {IPC_GLB_ENTER_DX_STATE =12 ,IPC_GLB_GET_MIXER_STREAM_INFO =13 ,/* Request mixer stream params */ IPC_GLB_DEBUG_LOG_MESSAGE =14 ,/* Message to or from the debug logger. */ +IPC_GLB_MODULE_OPERATION =15 ,/* Message to loadable fw module */ IPC_GLB_REQUEST_TRANSFER =16 ,/* < Request Transfer for host */ IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17, /* Maximum message number */ };
@@ -133,6 +143,16 @@ enum ipc_glb_reply { IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10, /* Source was not started. */ }; +enum ipc_module_operation { +IPC_MODULE_NOTIFICATION =0 , +IPC_MODULE_ENABLE =1 , +IPC_MODULE_DISABLE =2 , +IPC_MODULE_GET_PARAMETER =3 , +IPC_MODULE_SET_PARAMETER =4 , +IPC_MODULE_GET_INFO =5 , +IPC_MODULE_MAX_MESSAGE +}; +/* Stream Message - Types */ enum ipc_str_operation {IPC_STR_RESET =0 ,
@@ -352,6 +372,16 @@ static inline u32 msg_get_notify_reason(u32 msg)return (msg &IPC_STG_TYPE_MASK ) >>IPC_STG_TYPE_SHIFT ; } +static inline u32 msg_get_module_operation (u32 msg) +{ +return (msg &IPC_MODULE_OPERATION_MASK ) >>IPC_MODULE_OPERATION_SHIFT ; +} + +static inline u32 msg_get_module_id (u32 msg) +{ +return (msg &IPC_MODULE_ID_MASK ) >>IPC_MODULE_ID_SHIFT ; +} +u32 create_channel_map (enum sst_hsw_channel_config config) {switch (config) {
@@ -795,6 +825,31 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header)return 1 ; } +static int hsw_module_message (struct sst_hsw *hsw,u32 header) +{ +u32 operation, module_id; +int handled =0 ; + + operation =msg_get_module_operation (header); + module_id =msg_get_module_id (header); +dev_dbg (hsw->dev,"received module message header: 0x%8.8x\n" , + header); +dev_dbg (hsw->dev,"operation: 0x%8.8x module_id: 0x%8.8x\n" , + operation, module_id); + +switch (operation) { +case IPC_MODULE_NOTIFICATION : +dev_info (hsw->dev,"module notification received" ); + handled =1 ; +break ; +default : + handled =hsw_process_reply (hsw, header); +break ; + } + +return handled; +} +static int hsw_stream_message (struct sst_hsw *hsw,u32 header) {u32 stream_msg, stream_id, stage_type;
@@ -890,6 +945,9 @@ static int hsw_process_notification(struct sst_hsw *hsw)case IPC_GLB_DEBUG_LOG_MESSAGE : handled =hsw_log_message (hsw, header);break ; +case IPC_GLB_MODULE_OPERATION : + handled =hsw_module_message (hsw, header); +break ;default :dev_err (hsw->dev,"error: unexpected type %d hdr 0x%8.8x\n" , type, header);
@@ -1917,6 +1975,17 @@ bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id)return true; } +bool sst_hsw_is_module_active (struct sst_hsw *hsw,u32 module_id) +{ +struct sst_module *module; + + module =sst_module_get_from_id (hsw->dsp, module_id); +if (module !=NULL && module->state ==SST_MODULE_STATE_ACTIVE ) +return true; +else +return false; +} +int sst_hsw_module_load (struct sst_hsw *hsw,u32 module_id,u32 instance_id,char *name) {
@@ -1973,6 +2042,115 @@ out:return ret; } +int sst_hsw_module_enable (struct sst_hsw *hsw, +u32 module_id,u32 instance_id) +{ +int ret; +u32 header =0 ; +struct sst_hsw_ipc_module_config config; +struct sst_module *module; +struct sst_module_runtime *runtime; +struct device *dev = hsw->dev; +struct sst_dsp *dsp = hsw->dsp; + +if (!sst_hsw_is_module_loaded (hsw, module_id)) { +dev_dbg (dev,"module %d not loaded\n" , module_id); +return 0 ; + } + +if (sst_hsw_is_module_active (hsw, module_id)) { +dev_info (dev,"module %d already enabled\n" , module_id); +return 0 ; + } + + module =sst_module_get_from_id (dsp, module_id); +if (module ==NULL ) { +dev_err (dev,"module %d not valid\n" , module_id); +return -ENXIO ; + } + + runtime =sst_module_runtime_get_from_id (module, module_id); +if (runtime ==NULL ) { +dev_err (dev,"runtime %d not valid" , module_id); +return -ENXIO ; + } + + header =IPC_GLB_TYPE (IPC_GLB_MODULE_OPERATION ) | +IPC_MODULE_OPERATION (IPC_MODULE_ENABLE ) | +IPC_MODULE_ID (module_id); +dev_dbg (dev,"module enable header: %x\n" , header); + + config.map.module_entries_count =1 ; + config.map.module_entries[0 ].module_id = module->id; + config.map.module_entries[0 ].entry_point = module->entry; + + config.persistent_mem.offset = +sst_dsp_get_offset (dsp, + runtime->persistent_offset,SST_MEM_DRAM ); + config.persistent_mem.size = module->persistent_size; + + config.scratch_mem.offset = +sst_dsp_get_offset (dsp, + dsp->scratch_offset,SST_MEM_DRAM ); + config.scratch_mem.size = module->scratch_size; +dev_dbg (dev,"mod %d enable p:%d @ %x, s:%d @ %x, ep: %x" , + config.map.module_entries[0 ].module_id, + config.persistent_mem.size, + config.persistent_mem.offset, + config.scratch_mem.size, config.scratch_mem.offset, + config.map.module_entries[0 ].entry_point); + + ret =ipc_tx_message_wait (hsw, header, + &config,sizeof (config),NULL ,0 ); +if (ret <0 ) +dev_err (dev,"ipc: module enable failed - %d\n" , ret); +else { +dev_info (dev,"ipc: module enable success\n" ); + module->state =SST_MODULE_STATE_ACTIVE ; + } + +return ret; +} + +int sst_hsw_module_disable (struct sst_hsw *hsw, +u32 module_id,u32 instance_id) +{ +int ret; +u32 header; +struct sst_module *module; +struct device *dev = hsw->dev; +struct sst_dsp *dsp = hsw->dsp; + +if (!sst_hsw_is_module_loaded (hsw, module_id)) { +dev_dbg (dev,"module %d not loaded\n" , module_id); +return 0 ; + } + +if (!sst_hsw_is_module_active (hsw, module_id)) { +dev_info (dev,"module %d already disabled\n" , module_id); +return 0 ; + } + + module =sst_module_get_from_id (dsp, module_id); +if (module ==NULL ) { +dev_err (dev,"module %d not valid\n" , module_id); +return -ENXIO ; + } + + header =IPC_GLB_TYPE (IPC_GLB_MODULE_OPERATION ) | +IPC_MODULE_OPERATION (IPC_MODULE_DISABLE ) | +IPC_MODULE_ID (module_id); + + ret =ipc_tx_message_wait (hsw, header,NULL ,0 ,NULL ,0 ); +if (ret <0 ) +dev_err (dev,"module disable failed - %d\n" , ret); +else { +dev_info (dev,"module %d is now disabled\n" , module_id); + module->state =SST_MODULE_STATE_INITIALIZED ; + } +return ret; +} +static struct sst_dsp_device hsw_dev = { .thread = hsw_irq_thread, .ops = &haswell_ops,
sound/soc/intel/sst-haswell-ipc.h +11 -0
@@ -215,6 +215,12 @@ struct sst_hsw_fx_enable {struct sst_hsw_memory_info persistent_mem; } __attribute__((packed)); +struct sst_hsw_ipc_module_config { +struct sst_hsw_module_map map; +struct sst_hsw_memory_info persistent_mem; +struct sst_hsw_memory_info scratch_mem; +} __attribute__((packed)); +struct sst_hsw_get_fx_param {u32 parameter_id;u32 param_size;
@@ -470,9 +476,14 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw);/* fw module function */ void sst_hsw_init_module_state (struct sst_hsw *hsw);bool sst_hsw_is_module_loaded (struct sst_hsw *hsw,u32 module_id); +bool sst_hsw_is_module_active (struct sst_hsw *hsw,u32 module_id);int sst_hsw_module_load (struct sst_hsw *hsw,u32 module_id,u32 instance_id,char *name); +int sst_hsw_module_enable (struct sst_hsw *hsw, +u32 module_id,u32 instance_id); +int sst_hsw_module_disable (struct sst_hsw *hsw, +u32 module_id,u32 instance_id);/* runtime module management */ struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw,
Signature · 1 line
1.9.1
PATCH 4/8 ASoC: Intel: add kcontrol to enable/disable sound effect module waves
In reply to [email protected]From: "Lu, Han" <[email protected]>
Add kcontrol to enable/disable module waves. IPC is valid only when module is loaded.
sound/soc/intel/sst-haswell-pcm.c +39 -0
@@ -318,6 +318,42 @@ static int hsw_volume_get(struct snd_kcontrol *kcontrol,return 0 ; } +static int hsw_waves_switch_get (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *ucontrol) +{ +struct snd_soc_platform *platform =snd_soc_kcontrol_platform (kcontrol); +struct hsw_priv_data *pdata =snd_soc_platform_get_drvdata (platform); +struct sst_hsw *hsw = pdata->hsw; +enum sst_hsw_module_id id =SST_HSW_MODULE_WAVES ; + + ucontrol->value.integer.value[0 ] =sst_hsw_is_module_active (hsw, id); +return 0 ; +} + +static int hsw_waves_switch_put (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *ucontrol) +{ +struct snd_soc_platform *platform =snd_soc_kcontrol_platform (kcontrol); +struct hsw_priv_data *pdata =snd_soc_platform_get_drvdata (platform); +struct sst_hsw *hsw = pdata->hsw; +int ret =0 ; +enum sst_hsw_module_id id =SST_HSW_MODULE_WAVES ; +bool switch_on = (bool )ucontrol->value.integer.value[0 ]; + +if (sst_hsw_is_module_loaded (hsw, id)) { +if (switch_on ==sst_hsw_is_module_active (hsw, id)) +return 0 ; + +/* ipc is valid only when module is loaded */ +if (switch_on) + ret =sst_hsw_module_enable (hsw, id,0 ); +else + ret =sst_hsw_module_disable (hsw, id,0 ); + } + +return ret; +} +/* TLV used by both global and stream volumes */ static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1);
@@ -339,6 +375,9 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = {SOC_DOUBLE_EXT_TLV ("Mic Capture Volume" ,4 ,0 ,8 ,ARRAY_SIZE (volume_map) -1 ,0 , hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), +/* enable/disable module waves */ +SOC_SINGLE_BOOL_EXT ("Waves Switch" ,0 , + hsw_waves_switch_get, hsw_waves_switch_put), };/* Create DMA buffer page table for DSP */
Signature · 1 line
1.9.1
PATCH 5/8 ASoC: Intel: track module state on RTD3
In reply to [email protected]From: "Lu, Han" <[email protected]>
Track module state over suspend so it's state can be restored on resume.
sound/soc/intel/sst-haswell-ipc.c +19 -0
@@ -337,6 +337,10 @@ struct sst_hsw {/* FW log stream */ struct sst_hsw_log_stream log_stream; + +/* flags bit field to track module state when resume from RTD3, +* each bit represent state (enabled/disabled) of single module */ +u32 enabled_modules_rtd3; };#define CREATE_TRACE_POINTS
@@ -1986,6 +1990,21 @@ bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id)return false; } +void sst_hsw_set_module_enabled_rtd3 (struct sst_hsw *hsw,u32 module_id) +{ + hsw->enabled_modules_rtd3 |= (1 << module_id); +} + +void sst_hsw_set_module_disabled_rtd3 (struct sst_hsw *hsw,u32 module_id) +{ + hsw->enabled_modules_rtd3 &= ~(1 << module_id); +} + +bool sst_hsw_is_module_enabled_rtd3 (struct sst_hsw *hsw,u32 module_id) +{ +return hsw->enabled_modules_rtd3 & (1 << module_id); +} +int sst_hsw_module_load (struct sst_hsw *hsw,u32 module_id,u32 instance_id,char *name) {
sound/soc/intel/sst-haswell-ipc.h +3 -0
@@ -477,6 +477,9 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw);void sst_hsw_init_module_state (struct sst_hsw *hsw);bool sst_hsw_is_module_loaded (struct sst_hsw *hsw,u32 module_id);bool sst_hsw_is_module_active (struct sst_hsw *hsw,u32 module_id); +void sst_hsw_set_module_enabled_rtd3 (struct sst_hsw *hsw,u32 module_id); +void sst_hsw_set_module_disabled_rtd3 (struct sst_hsw *hsw,u32 module_id); +bool sst_hsw_is_module_enabled_rtd3 (struct sst_hsw *hsw,u32 module_id);int sst_hsw_module_load (struct sst_hsw *hsw,u32 module_id,u32 instance_id,char *name);
sound/soc/intel/sst-haswell-pcm.c +30 -1
@@ -326,7 +326,9 @@ static int hsw_waves_switch_get(struct snd_kcontrol *kcontrol,struct sst_hsw *hsw = pdata->hsw;enum sst_hsw_module_id id =SST_HSW_MODULE_WAVES ; - ucontrol->value.integer.value[0 ] =sst_hsw_is_module_active (hsw, id); + ucontrol->value.integer.value[0 ] = + (sst_hsw_is_module_active (hsw, id) || +sst_hsw_is_module_enabled_rtd3 (hsw, id));return 0 ; }
@@ -349,6 +351,16 @@ static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol, ret =sst_hsw_module_enable (hsw, id,0 ); else ret =sst_hsw_module_disable (hsw, id,0 ); + }else { +/* on RTD3, module is unloaded */ +if (switch_on ==sst_hsw_is_module_enabled_rtd3 (hsw, id)) +return 0 ; + +/* set flag for track */ +if (switch_on) +sst_hsw_set_module_enabled_rtd3 (hsw, id); +else +sst_hsw_set_module_disabled_rtd3 (hsw, id); }return ret;
@@ -1157,10 +1169,18 @@ static int hsw_pcm_runtime_suspend(struct device *dev) {struct hsw_priv_data *pdata =dev_get_drvdata (dev);struct sst_hsw *hsw = pdata->hsw; +int ret;if (pdata->pm_state >=HSW_PM_STATE_RTD3 )return 0 ; +/* fw modules will be unloaded on RTD3, set flag to trace */ +if (sst_hsw_is_module_active (hsw,SST_HSW_MODULE_WAVES )) { + ret =sst_hsw_module_disable (hsw,SST_HSW_MODULE_WAVES ,0 ); +if (ret <0 ) +return ret; +sst_hsw_set_module_enabled_rtd3 (hsw,SST_HSW_MODULE_WAVES ); + }sst_hsw_dsp_runtime_suspend (hsw);sst_hsw_dsp_runtime_sleep (hsw); pdata->pm_state =HSW_PM_STATE_RTD3 ;
@@ -1195,6 +1215,15 @@ static int hsw_pcm_runtime_resume(struct device *dev)else if (ret ==1 )/* no action required */ return 0 ; +/* check flag when resume */ +if (sst_hsw_is_module_enabled_rtd3 (hsw,SST_HSW_MODULE_WAVES )) { + ret =sst_hsw_module_enable (hsw,SST_HSW_MODULE_WAVES ,0 ); +if (ret <0 ) +return ret; +/* unset flag */ +sst_hsw_set_module_disabled_rtd3 (hsw,SST_HSW_MODULE_WAVES ); + } + pdata->pm_state =HSW_PM_STATE_D0 ;return ret; }
Signature · 1 line
1.9.1
PATCH 6/8 ASoC: Intel: add function to set parameter to sound effect module waves
In reply to [email protected]From: "Lu, Han" <[email protected]>
Add function to set parameters to module waves. The parameters can be set only when module is enabled, and parameter size is limited to 500 Bytes.
sound/soc/intel/sst-haswell-ipc.c +61 -0
@@ -2170,6 +2170,67 @@ int sst_hsw_module_disable(struct sst_hsw *hsw,return ret; } +int sst_hsw_module_set_param (struct sst_hsw *hsw, +u32 module_id,u32 instance_id,u32 parameter_id, +u32 param_size,char *param) +{ +int ret; +unsigned char *data =NULL ; +u32 header =0 ; +u32 payload_size =0 , transfer_parameter_size =0 ; +dma_addr_t dma_addr =0 ; +struct sst_hsw_transfer_parameter *parameter; +struct device *dev = hsw->dev; + + header =IPC_GLB_TYPE (IPC_GLB_MODULE_OPERATION ) | +IPC_MODULE_OPERATION (IPC_MODULE_SET_PARAMETER ) | +IPC_MODULE_ID (module_id); +dev_dbg (dev,"sst_hsw_module_set_param header=%x\n" , header); + + payload_size = param_size + +sizeof (struct sst_hsw_transfer_parameter ) - +sizeof (struct sst_hsw_transfer_list ); +dev_dbg (dev,"parameter size : %d\n" , param_size); +dev_dbg (dev,"payload size : %d\n" , payload_size); + +if (payload_size <=SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE ) { +/* short parameter, mailbox can contain data */ +dev_dbg (dev,"transfer parameter size : %d\n" , + transfer_parameter_size); + + transfer_parameter_size =ALIGN (payload_size,4 ); +dev_dbg (dev,"transfer parameter aligned size : %d\n" , + transfer_parameter_size); + + parameter =kzalloc (transfer_parameter_size,GFP_KERNEL ); +if (parameter ==NULL ) +return -ENOMEM ; + +memcpy (parameter->data, param, param_size); + }else { +dev_warn (dev,"transfer parameter size too large!" ); +return 0 ; + } + + parameter->parameter_id = parameter_id; + parameter->data_size = param_size; + + ret =ipc_tx_message_wait (hsw, header, + parameter, transfer_parameter_size ,NULL ,0 ); +if (ret <0 ) +dev_err (dev,"ipc: module set parameter failed - %d\n" , ret); +else +dev_info (dev,"ipc: module set parameter success\n" ); + +kfree (parameter); + +if (data) +dma_free_coherent (hsw->dsp->dma_dev, + param_size, (void *)data, dma_addr); + +return ret; +} +static struct sst_dsp_device hsw_dev = { .thread = hsw_irq_thread, .ops = &haswell_ops,
sound/soc/intel/sst-haswell-ipc.h +26 -0
@@ -37,6 +37,7 @@#define SST_HSW_IPC_MAX_PAYLOAD_SIZE 400#define SST_HSW_MAX_INFO_SIZE 64#define SST_HSW_BUILD_HASH_LENGTH 40 +#define SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE 500struct sst_hsw ;struct sst_hsw_stream ;
@@ -187,6 +188,28 @@ enum sst_hsw_performance_action { SST_HSW_PERF_STOP = 1, }; +struct sst_hsw_transfer_info { +uint32_t destination;/* destination address */ +uint32_t reverse:1 ;/* if 1 data flows from destination */ +uint32_t size:31 ;/* transfer size in bytes.*/ +uint16_t first_page_offset;/* offset to data in the first page. */ +uint8_t packed_pages;/* page addresses. Each occupies 20 bits */ +} __attribute__((packed)); + +struct sst_hsw_transfer_list { +uint32_t transfers_count; +struct sst_hsw_transfer_info transfers; +} __attribute__((packed)); + +struct sst_hsw_transfer_parameter { +uint32_t parameter_id; +uint32_t data_size; +union { +uint8_t data[1 ]; +struct sst_hsw_transfer_list transfer_list; + }; +} __attribute__((packed)); +/* SST firmware module info */ struct sst_hsw_module_info {u8 name[SST_HSW_MAX_INFO_SIZE ];
@@ -487,6 +510,9 @@ int sst_hsw_module_enable(struct sst_hsw *hsw, u32 module_id, u32 instance_id);int sst_hsw_module_disable (struct sst_hsw *hsw,u32 module_id,u32 instance_id); +int sst_hsw_module_set_param (struct sst_hsw *hsw, +u32 module_id,u32 instance_id,u32 parameter_id, +u32 param_size,char *param);/* runtime module management */ struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw,
Signature · 1 line
1.9.1
Mark Brown
maintainerRe: [PATCH 6/8] ASoC: Intel: add function to set parameter to sound effect module waves
sound/soc/intel/sst-haswell-ipc.c int sst_hsw_module_disable(struct sst_hsw *hsw, · line 2223
Quoted 4 lines · On Mon, Mar 02, 2015 at 03:36:16PM +0800, [email protected] wrote:
sound/soc/intel/sst-haswell-ipc.c +4
-0+if (ret <0 ) +dev_err (dev,"ipc: module set parameter failed - %d\n" , ret); +else +dev_info (dev,"ipc: module set parameter success\n" );
Logging on error is good but logging every time someone sets a control is going to get too noisy, please remove the print there.
PATCH 7/8 ASoC: Intel: add kcontrol to set parameter to sound effect module waves
In reply to [email protected]From: "Lu, Han" <[email protected]>
Each kcontrol command includes a line of parameters up to 128 bytes. kcontrol command to set param:
cset "name='Waves Set Param' <0x01,0xff,...>"
or
cset-bin-file "name='Waves Set Param' <path/to/binary/config/file>"
alsa-lib commit 6ea14c36 and f47480af are required for listed format.
sound/soc/intel/sst-haswell-ipc.h +1 -0
@@ -38,6 +38,7 @@#define SST_HSW_MAX_INFO_SIZE 64#define SST_HSW_BUILD_HASH_LENGTH 40#define SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE 500 +#define WAVES_PARAM_COUNT 128struct sst_hsw ;struct sst_hsw_stream ;
sound/soc/intel/sst-haswell-pcm.c +30 -0
@@ -366,6 +366,33 @@ static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol,return ret; } +static int hsw_waves_param_get (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *ucontrol) +{ +/* keep an empty function here to match alsa-lib calling */ +return 0 ; +} + +static int hsw_waves_param_put (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *ucontrol) +{ +struct snd_soc_platform *platform =snd_soc_kcontrol_platform (kcontrol); +struct hsw_priv_data *pdata =snd_soc_platform_get_drvdata (platform); +struct sst_hsw *hsw = pdata->hsw; +int ret; +enum sst_hsw_module_id id =SST_HSW_MODULE_WAVES ; +int param_id = ucontrol->value.bytes.data[0 ]; +int param_size =WAVES_PARAM_COUNT ; + +if (sst_hsw_is_module_loaded (hsw, id)) { +if (!sst_hsw_is_module_active (hsw, id)) +return 0 ; + ret =sst_hsw_module_set_param (hsw, id,0 , param_id, + param_size, ucontrol->value.bytes.data); + } +return ret; +} +/* TLV used by both global and stream volumes */ static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1);
@@ -390,6 +417,9 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = {/* enable/disable module waves */ SOC_SINGLE_BOOL_EXT ("Waves Switch" ,0 , hsw_waves_switch_get, hsw_waves_switch_put), +/* set parameters to module waves */ +SND_SOC_BYTES_EXT ("Waves Set Param" ,WAVES_PARAM_COUNT , + hsw_waves_param_get, hsw_waves_param_put), };/* Create DMA buffer page table for DSP */
Signature · 1 line
1.9.1
Mark Brown
maintainerRe: [PATCH 7/8] ASoC: Intel: add kcontrol to set parameter to sound effect module waves
sound/soc/intel/sst-haswell-pcm.c static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol, · line 374
Quoted 6 lines · On Mon, Mar 02, 2015 at 03:36:17PM +0800, [email protected] wrote:
sound/soc/intel/sst-haswell-pcm.c +6
-0+static int hsw_waves_param_get (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *ucontrol) +{ +/* keep an empty function here to match alsa-lib calling */ +return 0 ; +}
No, if it's valid to omit this we should be able to remove the function
- but I'd really expect to always be able to read the current state of any control. Applications should be able to do that and then write the value back without changing anything. Either we should actually read things back or this should return an error (which is presumably what the core does if the function is missing).
Re: [PATCH 7/8] ASoC: Intel: add kcontrol to set parameter to sound effect module waves
Quoted 10 lines
-----Original Message-----
From: Mark Brown [mailto:[email protected]]
Sent: Friday, March 6, 2015 7:35 PM
To: Lu, Han
Cc: [email protected]; Girdwood, Liam R
Subject: Re: [PATCH 7/8] ASoC: Intel: add kcontrol to set parameter to sound effect module wavesOn Mon, Mar 02, 2015 at 03:36:17PM +0800, [email protected] wrote:
Quoted 12 lines
sound/soc/intel/sst-haswell-pcm.c static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol, · line 374
Quoted 5 lines
sound/soc/intel/sst-haswell-pcm.c +5
-0+static int hsw_waves_param_get (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *ucontrol) { +/* keep an empty function here to match alsa-lib calling */ +return 0 ; +}No, if it's valid to omit this we should be able to remove the function
- but I'd really expect to always be able to read the current state of any control. Applications should be able to do that and then write the value back without changing anything. Either we should actually read things back or this should return an error (which is presumably what the core does if the function is missing).
[Han Lu] OK. I made patch v2 against current code, and remove unnecessary logs. For the read back kcontrol, I do not modify patch 7/8 but add actual read back code on patch 8/8, (merge patch 7 and 8 may make the patch too long and unclear?) please review. Thanks.
PATCH 8/8 ASoC: Intel: enable parameter restore for sound effect module waves
In reply to [email protected]From: "Lu, Han" <[email protected]>
The parameters in DSP will lost on RTD3. To fix this, store parameter lines in a buffer, and put the buffer content to DSP when resume from RTD3. The size of buffer is 160 parameter lines.
And add kcontrol command to reset the buffer:
cset "name='Waves Set Param' 0xff"
sound/soc/intel/sst-haswell-ipc.c +38 -0
@@ -341,6 +341,10 @@ struct sst_hsw {/* flags bit field to track module state when resume from RTD3, * each bit represent state (enabled/disabled) of single module */ u32 enabled_modules_rtd3; + +/* buffer to store parameter lines */ +u32 param_idx; +u8 param_buf[WAVES_PARAM_LINES ][WAVES_PARAM_COUNT ]; };#define CREATE_TRACE_POINTS
@@ -2005,6 +2009,37 @@ bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id)return hsw->enabled_modules_rtd3 & (1 << module_id); } +void sst_hsw_reset_param_buf (struct sst_hsw *hsw) +{ + hsw->param_idx =0 ; +memset ((void *)hsw->param_buf,0 ,sizeof (hsw->param_buf)); +} + +int sst_hsw_store_param_line (struct sst_hsw *hsw,u8 *buf) +{ +if (hsw->param_idx >WAVES_PARAM_LINES -1 ) { +dev_warn (hsw->dev,"warning: param buffer overflow!\n" ); +return 0 ; + } +memcpy (hsw->param_buf[hsw->param_idx], buf,WAVES_PARAM_COUNT ); + hsw->param_idx++; +return 0 ; +} + +int sst_hsw_launch_param_buf (struct sst_hsw *hsw) +{ +int ret, idx; + +for (idx =0 ; idx < hsw->param_idx; idx++) { + ret =sst_hsw_module_set_param (hsw, +SST_HSW_MODULE_WAVES ,0 , hsw->param_buf[idx][0 ], +WAVES_PARAM_COUNT , hsw->param_buf[idx]); +if (ret <0 ) +return ret; + } +return 0 ; +} +int sst_hsw_module_load (struct sst_hsw *hsw,u32 module_id,u32 instance_id,char *name) {
@@ -2305,6 +2340,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)if (ret <0 ) goto boot_err; +/* init param buffer */ +sst_hsw_reset_param_buf (hsw); +/* wait for DSP boot completion */ sst_dsp_boot (hsw->dsp); ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,
sound/soc/intel/sst-haswell-ipc.h +4 -0
@@ -39,6 +39,7 @@#define SST_HSW_BUILD_HASH_LENGTH 40#define SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE 500#define WAVES_PARAM_COUNT 128 +#define WAVES_PARAM_LINES 160struct sst_hsw ;struct sst_hsw_stream ;
@@ -504,6 +505,9 @@ bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id);void sst_hsw_set_module_enabled_rtd3 (struct sst_hsw *hsw,u32 module_id);void sst_hsw_set_module_disabled_rtd3 (struct sst_hsw *hsw,u32 module_id);bool sst_hsw_is_module_enabled_rtd3 (struct sst_hsw *hsw,u32 module_id); +void sst_hsw_reset_param_buf (struct sst_hsw *hsw); +int sst_hsw_store_param_line (struct sst_hsw *hsw,u8 *buf); +int sst_hsw_launch_param_buf (struct sst_hsw *hsw);int sst_hsw_module_load (struct sst_hsw *hsw,u32 module_id,u32 instance_id,char *name);
sound/soc/intel/sst-haswell-pcm.c +15 -0
@@ -384,6 +384,17 @@ static int hsw_waves_param_put(struct snd_kcontrol *kcontrol,int param_id = ucontrol->value.bytes.data[0 ];int param_size =WAVES_PARAM_COUNT ; +/* clear param buffer and reset buffer index */ +if (param_id ==0xFF ) { +sst_hsw_reset_param_buf (hsw); +return 0 ; + } + +/* store params into buffer */ + ret =sst_hsw_store_param_line (hsw, ucontrol->value.bytes.data); +if (ret <0 ) +return ret; +if (sst_hsw_is_module_loaded (hsw, id)) {if (!sst_hsw_is_module_active (hsw, id))return 0 ;
@@ -1250,6 +1261,10 @@ static int hsw_pcm_runtime_resume(struct device *dev) ret =sst_hsw_module_enable (hsw,SST_HSW_MODULE_WAVES ,0 );if (ret <0 )return ret; +/* put parameters from buffer to dsp */ + ret =sst_hsw_launch_param_buf (hsw); +if (ret <0 ) +return ret;/* unset flag */ sst_hsw_set_module_disabled_rtd3 (hsw,SST_HSW_MODULE_WAVES ); }
Signature · 1 line
1.9.1
Mark Brown
maintainerQuoted 5 lines · On Mon, Mar 02, 2015 at 03:36:11PM +0800, [email protected] wrote:
From: "Lu, Han" <[email protected]>
Add a general method to load firmware image, and apply to base firmware image loading. With the method, the driver will support loading multiple different modules in order to support different features.
This doesn't apply against current code, please check and resend.