387 lines
9.6 KiB
Diff
387 lines
9.6 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Leoni Prodduvaka <leoni.prodduvaka@intel.com>
|
|
Date: Mon, 6 Feb 2017 22:16:04 +0530
|
|
Subject: [PATCH] ASoC: Intel: Skylake: Parse the fw property
|
|
|
|
The value returned by the FW CONFIG IPC is in the form of a TLV.
|
|
It contains information about fw version, memory reclaim,
|
|
mailbox size etc.,
|
|
Parse the fw property, it could be used during runtime operations.
|
|
|
|
Change-Id: Ie366c59b8ba103f38e8a8e67e1aa679123e77c05
|
|
Signed-off-by: Leoni Prodduvaka
|
|
Reviewed-on:
|
|
Reviewed-by: R, Dharageswari <dharageswari.r@intel.com>
|
|
Reviewed-by: Diwakar, Praveen <praveen.diwakar@intel.com>
|
|
Reviewed-by: Koul, Vinod <vinod.koul@intel.com>
|
|
Tested-by: Sm, Bhadur A <bhadur.a.sm@intel.com>
|
|
---
|
|
sound/soc/intel/skylake/skl-messages.c | 5 +
|
|
sound/soc/intel/skylake/skl-sst-dsp.h | 32 ++++
|
|
sound/soc/intel/skylake/skl-sst-ipc.h | 58 +++++++
|
|
sound/soc/intel/skylake/skl-sst-utils.c | 195 +++++++++++++++++++++++-
|
|
4 files changed, 289 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
|
|
index 4a0ad29..e0d6f74 100644
|
|
--- a/sound/soc/intel/skylake/skl-messages.c
|
|
+++ b/sound/soc/intel/skylake/skl-messages.c
|
|
@@ -1158,6 +1158,8 @@ int skl_free_dsp(struct skl *skl)
|
|
{
|
|
struct hdac_bus *bus = skl_to_bus(skl);
|
|
struct skl_sst *ctx = skl->skl_sst;
|
|
+ struct skl_fw_property_info fw_property = skl->skl_sst->fw_property;
|
|
+ struct skl_scheduler_config sch_config = fw_property.scheduler_config;
|
|
|
|
/* disable ppcap interrupt */
|
|
snd_hdac_ext_bus_ppcap_int_enable(bus, false);
|
|
@@ -1170,6 +1172,9 @@ int skl_free_dsp(struct skl *skl)
|
|
if (ctx->dsp->addr.lpe)
|
|
iounmap(ctx->dsp->addr.lpe);
|
|
|
|
+ kfree(fw_property.dma_config);
|
|
+ kfree(sch_config.sys_tick_cfg);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h
|
|
index ea6e57e..df37765 100644
|
|
--- a/sound/soc/intel/skylake/skl-sst-dsp.h
|
|
+++ b/sound/soc/intel/skylake/skl-sst-dsp.h
|
|
@@ -127,8 +127,40 @@ struct skl_lib_info;
|
|
#define SKL_ADSPCS_CPA_SHIFT 24
|
|
#define SKL_ADSPCS_CPA_MASK(cm) ((cm) << SKL_ADSPCS_CPA_SHIFT)
|
|
|
|
+/* Header size is in number of bytes */
|
|
+#define SKL_TLV_HEADER_SIZE 8
|
|
+struct skl_tlv_message {
|
|
+ u32 type;
|
|
+ u32 length;
|
|
+ char data[0];
|
|
+} __packed;
|
|
+
|
|
#define DSP_BUF PAGE_SIZE
|
|
|
|
+enum skl_fw_info_type {
|
|
+ SKL_FW_VERSION = 0,
|
|
+ SKL_MEMORY_RECLAIMED,
|
|
+ SKL_SLOW_CLOCK_FREQ_HZ,
|
|
+ SKL_FAST_CLOCK_FREQ_HZ,
|
|
+ SKL_DMA_BUFFER_CONFIG,
|
|
+ SKL_ALH_SUPPORT_LEVEL,
|
|
+ SKL_IPC_DL_MAILBOX_BYTES,
|
|
+ SKL_IPC_UL_MAILBOX_BYTES,
|
|
+ SKL_TRACE_LOG_BYTES,
|
|
+ SKL_MAX_PPL_COUNT,
|
|
+ SKL_MAX_ASTATE_COUNT,
|
|
+ SKL_MAX_MODULE_PIN_COUNT,
|
|
+ SKL_MODULES_COUNT,
|
|
+ SKL_MAX_MOD_INST_COUNT,
|
|
+ SKL_MAX_LL_TASKS_PER_PRI_COUNT,
|
|
+ SKL_LL_PRI_COUNT,
|
|
+ SKL_MAX_DP_TASKS_COUNT,
|
|
+ SKL_MAX_LIBS_COUNT,
|
|
+ SKL_SCHEDULER_CONFIG,
|
|
+ SKL_XTAL_FREQ_HZ,
|
|
+ SKL_CLOCKS_CONFIG,
|
|
+};
|
|
+
|
|
/* DSP Core state */
|
|
enum skl_dsp_states {
|
|
SKL_DSP_RUNNING = 1,
|
|
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h
|
|
index 0740146..7700b5c 100644
|
|
--- a/sound/soc/intel/skylake/skl-sst-ipc.h
|
|
+++ b/sound/soc/intel/skylake/skl-sst-ipc.h
|
|
@@ -133,6 +133,61 @@ struct bra_conf {
|
|
struct skl_pipe *cp_pipe;
|
|
};
|
|
|
|
+struct skl_fw_version {
|
|
+ u16 major;
|
|
+ u16 minor;
|
|
+ u16 hotfix;
|
|
+ u16 build;
|
|
+};
|
|
+
|
|
+struct skl_dma_buff_config {
|
|
+ u32 min_size_bytes;
|
|
+ u32 max_size_bytes;
|
|
+};
|
|
+
|
|
+enum skl_alh_support_level {
|
|
+ ALH_NO_SUPPORT = 0x00000,
|
|
+ ALH_CAVS_1_8_CNL = 0x10000,
|
|
+};
|
|
+
|
|
+struct skl_clk_config {
|
|
+ u32 clock_source;
|
|
+ u32 clock_param_mask;
|
|
+};
|
|
+
|
|
+struct skl_scheduler_config {
|
|
+ u32 sys_tick_multiplier;
|
|
+ u32 sys_tick_divider;
|
|
+ u32 sys_tick_source;
|
|
+ u32 sys_tick_cfg_length;
|
|
+ u32 *sys_tick_cfg;
|
|
+};
|
|
+
|
|
+struct skl_fw_property_info {
|
|
+ struct skl_fw_version version;
|
|
+ u32 memory_reclaimed;
|
|
+ u32 slow_clock_freq_hz;
|
|
+ u32 fast_clock_freq_hz;
|
|
+ enum skl_alh_support_level alh_support;
|
|
+ u32 ipc_dl_mailbox_bytes;
|
|
+ u32 ipc_ul_mailbox_bytes;
|
|
+ u32 trace_log_bytes;
|
|
+ u32 max_ppl_count;
|
|
+ u32 max_astate_count;
|
|
+ u32 max_module_pin_count;
|
|
+ u32 modules_count;
|
|
+ u32 max_mod_inst_count;
|
|
+ u32 max_ll_tasks_per_pri_count;
|
|
+ u32 ll_pri_count;
|
|
+ u32 max_dp_tasks_count;
|
|
+ u32 max_libs_count;
|
|
+ u32 xtal_freq_hz;
|
|
+ struct skl_clk_config clk_config;
|
|
+ struct skl_scheduler_config scheduler_config;
|
|
+ u32 num_dma_cfg;
|
|
+ struct skl_dma_buff_config *dma_config;
|
|
+};
|
|
+
|
|
struct skl_sst {
|
|
struct device *dev;
|
|
struct sst_dsp *dsp;
|
|
@@ -189,6 +244,9 @@ struct skl_sst {
|
|
|
|
/* BRA configuration data */
|
|
struct bra_conf *bra_pipe_data;
|
|
+
|
|
+ /* firmware configuration information */
|
|
+ struct skl_fw_property_info fw_property;
|
|
};
|
|
|
|
struct skl_ipc_init_instance_msg {
|
|
diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c
|
|
index 59fb24b..2bd5565 100644
|
|
--- a/sound/soc/intel/skylake/skl-sst-utils.c
|
|
+++ b/sound/soc/intel/skylake/skl-sst-utils.c
|
|
@@ -446,6 +446,192 @@ void skl_release_library(struct skl_lib_info *linfo, int lib_count)
|
|
}
|
|
}
|
|
}
|
|
+static int skl_fill_sch_cfg(
|
|
+ struct skl_fw_property_info *fw_property,
|
|
+ u32 *src)
|
|
+{
|
|
+ struct skl_scheduler_config *sch_config =
|
|
+ &(fw_property->scheduler_config);
|
|
+
|
|
+ sch_config->sys_tick_multiplier = *src;
|
|
+ sch_config->sys_tick_divider = *(src + 1);
|
|
+ sch_config->sys_tick_source = *(src + 2);
|
|
+ sch_config->sys_tick_cfg_length = *(src + 3);
|
|
+
|
|
+ if (sch_config->sys_tick_cfg_length > 0) {
|
|
+ sch_config->sys_tick_cfg =
|
|
+ kcalloc(sch_config->sys_tick_cfg_length,
|
|
+ sizeof(*sch_config->sys_tick_cfg),
|
|
+ GFP_KERNEL);
|
|
+
|
|
+ if (!sch_config->sys_tick_cfg)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ memcpy(sch_config->sys_tick_cfg,
|
|
+ src + 4,
|
|
+ sch_config->sys_tick_cfg_length *
|
|
+ sizeof(*sch_config->sys_tick_cfg));
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int skl_fill_dma_cfg(struct skl_tlv_message *message,
|
|
+ struct skl_fw_property_info *fw_property, u32 *src)
|
|
+{
|
|
+ struct skl_dma_buff_config dma_buff_cfg;
|
|
+
|
|
+ fw_property->num_dma_cfg = message->length /
|
|
+ sizeof(dma_buff_cfg);
|
|
+
|
|
+ if (fw_property->num_dma_cfg > 0) {
|
|
+ fw_property->dma_config =
|
|
+ kcalloc(fw_property->num_dma_cfg,
|
|
+ sizeof(dma_buff_cfg),
|
|
+ GFP_KERNEL);
|
|
+
|
|
+ if (!fw_property->dma_config)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ memcpy(fw_property->dma_config, src,
|
|
+ message->length);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int skl_parse_fw_config_info(struct sst_dsp *ctx,
|
|
+ u8 *src, int limit)
|
|
+{
|
|
+ struct skl_tlv_message *message;
|
|
+ int offset = 0, shift, ret = 0;
|
|
+ u32 *value;
|
|
+ struct skl_sst *skl = ctx->thread_context;
|
|
+ struct skl_fw_property_info *fw_property = &skl->fw_property;
|
|
+ enum skl_fw_info_type type;
|
|
+ struct skl_scheduler_config *sch_config =
|
|
+ &fw_property->scheduler_config;
|
|
+
|
|
+ while (offset < limit) {
|
|
+
|
|
+ message = (struct skl_tlv_message *)src;
|
|
+ if (message == NULL)
|
|
+ break;
|
|
+
|
|
+ /* Skip TLV header to read value */
|
|
+ src += sizeof(*message);
|
|
+
|
|
+ value = (u32 *)src;
|
|
+ type = message->type;
|
|
+
|
|
+ switch (type) {
|
|
+ case SKL_FW_VERSION:
|
|
+ memcpy(&fw_property->version, value,
|
|
+ sizeof(fw_property->version));
|
|
+ break;
|
|
+
|
|
+ case SKL_MEMORY_RECLAIMED:
|
|
+ fw_property->memory_reclaimed = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_SLOW_CLOCK_FREQ_HZ:
|
|
+ fw_property->slow_clock_freq_hz = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_FAST_CLOCK_FREQ_HZ:
|
|
+ fw_property->fast_clock_freq_hz = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_DMA_BUFFER_CONFIG:
|
|
+ ret = skl_fill_dma_cfg(message, fw_property, value);
|
|
+ if (ret < 0)
|
|
+ goto err;
|
|
+ break;
|
|
+
|
|
+ case SKL_ALH_SUPPORT_LEVEL:
|
|
+ fw_property->alh_support = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_IPC_DL_MAILBOX_BYTES:
|
|
+ fw_property->ipc_dl_mailbox_bytes = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_IPC_UL_MAILBOX_BYTES:
|
|
+ fw_property->ipc_ul_mailbox_bytes = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_TRACE_LOG_BYTES:
|
|
+ fw_property->trace_log_bytes = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_MAX_PPL_COUNT:
|
|
+ fw_property->max_ppl_count = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_MAX_ASTATE_COUNT:
|
|
+ fw_property->max_astate_count = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_MAX_MODULE_PIN_COUNT:
|
|
+ fw_property->max_module_pin_count = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_MODULES_COUNT:
|
|
+ fw_property->modules_count = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_MAX_MOD_INST_COUNT:
|
|
+ fw_property->max_mod_inst_count = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_MAX_LL_TASKS_PER_PRI_COUNT:
|
|
+ fw_property->max_ll_tasks_per_pri_count = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_LL_PRI_COUNT:
|
|
+ fw_property->ll_pri_count = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_MAX_DP_TASKS_COUNT:
|
|
+ fw_property->max_dp_tasks_count = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_MAX_LIBS_COUNT:
|
|
+ fw_property->max_libs_count = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_SCHEDULER_CONFIG:
|
|
+ ret = skl_fill_sch_cfg(fw_property, value);
|
|
+ if (ret < 0)
|
|
+ goto err;
|
|
+ break;
|
|
+
|
|
+ case SKL_XTAL_FREQ_HZ:
|
|
+ fw_property->xtal_freq_hz = *value;
|
|
+ break;
|
|
+
|
|
+ case SKL_CLOCKS_CONFIG:
|
|
+ memcpy(&(fw_property->clk_config), value,
|
|
+ message->length);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ dev_err(ctx->dev, "Invalid fw info type:%d !!\n",
|
|
+ type);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ shift = message->length + sizeof(*message);
|
|
+ offset += shift;
|
|
+ /* skip over to next tlv data */
|
|
+ src += message->length;
|
|
+ }
|
|
+err:
|
|
+ if (ret < 0) {
|
|
+ kfree(fw_property->dma_config);
|
|
+ kfree(sch_config->sys_tick_cfg);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
|
|
int skl_get_firmware_configuration(struct sst_dsp *ctx)
|
|
{
|
|
@@ -466,9 +652,16 @@ int skl_get_firmware_configuration(struct sst_dsp *ctx)
|
|
|
|
ret = skl_ipc_get_large_config(&skl->ipc, &msg,
|
|
(u32 *)ipc_data, NULL, 0, &rx_bytes);
|
|
- if (ret < 0)
|
|
+ if (ret < 0) {
|
|
dev_err(ctx->dev, "failed to get fw configuration !!!\n");
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ ret = skl_parse_fw_config_info(ctx, ipc_data, rx_bytes);
|
|
+ if (ret < 0)
|
|
+ dev_err(ctx->dev, "failed to parse configuration !!!\n");
|
|
|
|
+err:
|
|
kfree(ipc_data);
|
|
return ret;
|
|
}
|
|
--
|
|
https://clearlinux.org
|
|
|