clear-pkgs-linux-iot-lts2018/0309-ASoC-Intel-Skylake-Par...

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