From patchwork Sat Apr 18 20:57:33 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vinod Koul X-Patchwork-Id: 6237761 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 6ADD79F313 for ; Sat, 18 Apr 2015 21:07:41 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id F2FB7203DF for ; Sat, 18 Apr 2015 21:07:39 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 0E69C203C0 for ; Sat, 18 Apr 2015 21:07:38 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 3AEDD265AEF; Sat, 18 Apr 2015 23:07:37 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,NO_DNS_FOR_FROM, UNPARSEABLE_RELAY autolearn=no version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 73BBF265B63; Sat, 18 Apr 2015 23:04:39 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id BE2D3265AFE; Sat, 18 Apr 2015 23:04:37 +0200 (CEST) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by alsa0.perex.cz (Postfix) with ESMTP id CDE0226530C for ; Sat, 18 Apr 2015 23:02:58 +0200 (CEST) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga102.fm.intel.com with ESMTP; 18 Apr 2015 14:02:58 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.11,600,1422950400"; d="scan'208";a="711505264" Received: from vkoul-udesk3.iind.intel.com ([10.223.84.65]) by fmsmga002.fm.intel.com with ESMTP; 18 Apr 2015 14:02:55 -0700 From: Vinod Koul To: alsa-devel@alsa-project.org Date: Sun, 19 Apr 2015 02:27:33 +0530 Message-Id: <1429390653-8194-8-git-send-email-vinod.koul@intel.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1429390653-8194-1-git-send-email-vinod.koul@intel.com> References: <1429390653-8194-1-git-send-email-vinod.koul@intel.com> Cc: tiwai@suse.de, Hardik T Shah , liam.r.girdwood@linux.intel.com, patches.audio@intel.com, broonie@kernel.org, Jeeja KP , Vinod Koul Subject: [alsa-devel] [RFC 7/7] ASoC: hda: Apply dai params_fixup for DSP widgets X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP From: Jeeja KP DSP widgets configuration needs to be changed based on hw_params or hw_params_fixup. Add support where dai configuration is store in private data and apply to widget based on fixup. Signed-off-by: Hardik T Shah Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul --- sound/soc/hda/Makefile | 2 +- sound/soc/hda/hda_dsp_controls.c | 213 +++++++++++++++++++++++++++++++++++- sound/soc/hda/hda_dsp_ssp_config.c | 15 ++- sound/soc/hda/hda_skl.h | 75 +++++++++++++ 4 files changed, 298 insertions(+), 7 deletions(-) diff --git a/sound/soc/hda/Makefile b/sound/soc/hda/Makefile index 668c831b196e..c8be01816157 100644 --- a/sound/soc/hda/Makefile +++ b/sound/soc/hda/Makefile @@ -1,5 +1,5 @@ snd-soc-hda-skl-objs := hda_skl.o hda_skl_pcm.o hda_soc_dsp.o \ -hda_dsp_controls.o +hda_dsp_controls.o hda_dsp_ssp_config.o obj-$(CONFIG_SND_SOC_HDA_SKL) += snd-soc-hda-skl.o diff --git a/sound/soc/hda/hda_dsp_controls.c b/sound/soc/hda/hda_dsp_controls.c index ee53227fa751..3c23fdc3e14b 100644 --- a/sound/soc/hda/hda_dsp_controls.c +++ b/sound/soc/hda/hda_dsp_controls.c @@ -25,8 +25,27 @@ #include #include #include "hda_dsp_controls.h" +#include "hda_dsp_ssp_config.h" #include "hda_skl.h" +#define CH_FIXUP (1 << 0) +#define RATE_FIXUP (1 << 1) +#define FMT_FIXUP (1 << 2) + +#define CH_FIXUP_MASK (1 << 0) +#define RATE_FIXUP_MASK (1 << 1) +#define FMT_FIXUP_MASK (1 << 2) + +#define CH_CONVERTER (1 << 0) +#define RATE_CONVERTER (1 << 1) +#define FMT_CONVERTER (1 << 2) + +#define CH_CONVERTER_MASK (1 << 0) +#define RATE_CONVERTER_MASK (1 << 1) +#define FMT_CONVERTER_MASK (1 << 2) + +#define REGS_OFFSET_CPR_BLOB 8 + static int is_hda_widget_type(struct snd_soc_dapm_widget *w) { return ((w->id == snd_soc_dapm_dai_link) || @@ -161,6 +180,117 @@ static bool hda_sst_is_pipe_mcps_available(struct hda_platform_info *pinfo, return true; } +static struct snd_soc_dai *hda_find_dai_in(struct list_head *sinks) +{ + struct snd_soc_dapm_path *p; + struct snd_soc_dai *dai = NULL; + list_for_each_entry(p, sinks, list_source) { + if (p->connect) { + if (p->sink->id == snd_soc_dapm_dai_in || + p->sink->id == snd_soc_dapm_dai_out) { + dai = p->sink->priv; + return dai; + } + dai = hda_find_dai_in(&p->sink->sinks); + if (dai) + return dai; + } + } + return dai; +} + +static struct snd_soc_dai *hda_find_dai_out(struct list_head *sources) +{ + struct snd_soc_dapm_path *p; + struct snd_soc_dai *dai = NULL; + list_for_each_entry(p, sources, list_sink) { + if (p->connect) { + if (p->source->id == snd_soc_dapm_dai_in || + p->source->id == snd_soc_dapm_dai_out) { + dai = p->source->priv; + break; + } + dai = hda_find_dai_out(&p->source->sources); + if (dai) + return dai; + } + } + return dai; +} + +static struct hda_dai_config *hda_sst_get_dai_config(struct snd_soc_dapm_widget *w, + struct ssth_module_config *mconfig, struct ssth_lib *ctx) +{ + struct snd_soc_dai *dai = NULL; + struct hda_soc_bus *hda = NULL; + + if (mconfig->hw_conn_type == SSTH_CONN_SOURCE) { + if (mconfig->pipe->conn_type == SSTH_PIPE_CONN_TYPE_BE) + dai = hda_find_dai_in(&w->sinks); + else if (mconfig->pipe->conn_type == SSTH_PIPE_CONN_TYPE_FE) + dai = hda_find_dai_out(&w->sources); + } else if (mconfig->hw_conn_type == SSTH_CONN_SINK) { + if (mconfig->pipe->conn_type == SSTH_PIPE_CONN_TYPE_BE) + dai = hda_find_dai_out(&w->sources); + else if (mconfig->pipe->conn_type == SSTH_PIPE_CONN_TYPE_FE) + dai = hda_find_dai_in(&w->sinks); + } + if (!dai) { + dev_dbg(ctx->dev, "Dai not found for widget %s\n", w->name); + return NULL; + } + dev_dbg(ctx->dev, "Dai found %s for widget %s\n", + dai->name, w->name); + hda = dev_get_drvdata(dai->dev); + return &hda->pinfo->dai_config[dai->id - 1]; + +} + +static void hda_dump_mconfig(struct ssth_lib *ctx, + struct ssth_module_config *mcfg) +{ + dev_dbg(ctx->dev, "Dumping Mconfig\n"); + dev_dbg(ctx->dev, "Input Format:\n"); + dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt.channels); + dev_dbg(ctx->dev, "sampling_freq = %d\n", mcfg->in_fmt.sampling_freq); + dev_dbg(ctx->dev, "channel_config = %d\n", mcfg->in_fmt.channel_config); + dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt.valid_bit_depth); + dev_dbg(ctx->dev, "Output Format:\n"); + dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt.channels); + dev_dbg(ctx->dev, "sampling_freq = %d\n", mcfg->out_fmt.sampling_freq); + dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt.valid_bit_depth); + dev_dbg(ctx->dev, "channel_config = %d\n", mcfg->out_fmt.channel_config); +} +static void hda_dump_dai_config(struct ssth_lib *ctx, + struct hda_dai_config *cfg) +{ + struct hda_ssp_dai_config *ssp_cfg = &cfg->ssp_dai_config; + dev_dbg(ctx->dev, "Dumping DAI config\n"); + dev_dbg(ctx->dev, "slot_width = %d\n", ssp_cfg->slot_width); + dev_dbg(ctx->dev, "Slot = %d\n", ssp_cfg->slots); + dev_dbg(ctx->dev, "ssp_mode = %d\n", ssp_cfg->ssp_mode); + dev_dbg(ctx->dev, "sampling rate = %d\n", cfg->sampling_rate); + dev_dbg(ctx->dev, "s_fmt = %d\n", cfg->s_fmt); + dev_dbg(ctx->dev, "bclk_invert = %d\n", ssp_cfg->bclk_invert); + dev_dbg(ctx->dev, "fs_invert = %d\n", ssp_cfg->fs_invert); + dev_dbg(ctx->dev, "num_channels = %d\n", cfg->num_channels); + dev_dbg(ctx->dev, "fs_slave = %d\n", ssp_cfg->fs_slave); + dev_dbg(ctx->dev, "bclk_slave = %d\n", ssp_cfg->bclk_slave); +} + +static void hda_update_mconfig(struct ssth_module_format *fmt, + struct hda_dai_config *ssp_cfg, + int params_fixup) +{ + if (params_fixup & RATE_FIXUP_MASK) + fmt->sampling_freq = ssp_cfg->sampling_rate; + if (params_fixup & CH_FIXUP_MASK) + fmt->channels = ssp_cfg->num_channels; + if (params_fixup & FMT_FIXUP_MASK) + fmt->valid_bit_depth = ssp_cfg->s_fmt; + +} + static void hda_update_slot_map(struct ssth_lib *ctx, struct ssth_module_config *m_cfg) { @@ -213,6 +343,87 @@ static void hda_update_ch_config(struct ssth_module_config *m_cfg) } +static void hda_update_buffer_size(struct ssth_lib *ctx, + struct ssth_module_config *mcfg) +{ + int multiplier = 1; + + if (mcfg->id.module_id == SSTH_SRCINT_MODULE) + multiplier = 5; + mcfg->ibs = (mcfg->in_fmt.sampling_freq / 1000) * + (mcfg->in_fmt.channels) * + (mcfg->in_fmt.bit_depth >> 3) * + multiplier; + + mcfg->obs = (mcfg->out_fmt.sampling_freq / 1000) * + (mcfg->out_fmt.channels) * + (mcfg->out_fmt.bit_depth >> 3) * + multiplier; +} + +static void hda_sst_configure_widget(struct snd_soc_dapm_widget *w, + struct ssth_lib *ctx, struct hda_platform_info *pinfo) +{ + struct ssth_module_config *m_cfg = w->priv; + struct hda_dai_config *dai_config; + union ssth_ssp_dma_node dma_id; + unsigned int *regs = NULL; + + dai_config = hda_sst_get_dai_config(w, m_cfg, ctx); + if (!dai_config) + return; + + if (m_cfg->id.module_id == SSTH_COPIER_MODULE && + m_cfg->pipe->conn_type == SSTH_PIPE_CONN_TYPE_BE && + dai_config->dai_type == HDA_DAI_TYPE_SSP) { + dma_id.val = 0; + dma_id.dma_node.i2s_instance = + dai_config->ssp_dai_config.i2s_instance; + m_cfg->dma_id = dma_id.val; + regs = m_cfg->formats_config.caps; + } + if (!m_cfg->params_fixup) + return; + + hda_dump_dai_config(ctx, dai_config); + dev_dbg(ctx->dev, "Mconfig for widget %s BEFORE updation\n", w->name); + hda_dump_mconfig(ctx, m_cfg); + + /* Based on whether the widget is in FE pipe or BE PIPE and playback direction + * or capture direction, fixups applied will be changed + */ + if ((m_cfg->pipe->conn_type == SSTH_PIPE_CONN_TYPE_FE && + (m_cfg->hw_conn_type == SSTH_CONN_SINK)) || + (m_cfg->pipe->conn_type == SSTH_PIPE_CONN_TYPE_BE && + m_cfg->hw_conn_type == SSTH_CONN_SOURCE)) { + hda_update_mconfig(&m_cfg->out_fmt, dai_config, + m_cfg->params_fixup); + hda_update_mconfig(&m_cfg->in_fmt, dai_config, + (~m_cfg->converter) & m_cfg->params_fixup); + } + if ((m_cfg->pipe->conn_type == SSTH_PIPE_CONN_TYPE_BE && + (m_cfg->hw_conn_type == SSTH_CONN_SINK)) || + (m_cfg->pipe->conn_type == SSTH_PIPE_CONN_TYPE_FE && + m_cfg->hw_conn_type == SSTH_CONN_SOURCE)) { + hda_update_mconfig(&m_cfg->in_fmt, dai_config, + m_cfg->params_fixup); + hda_update_mconfig(&m_cfg->out_fmt, dai_config, + (~m_cfg->converter) & m_cfg->params_fixup); + } + + hda_update_ch_config(m_cfg); + hda_update_buffer_size(ctx, m_cfg); + if (regs) { + /* Slot map only needs to be updated for copier */ + hda_update_slot_map(ctx, m_cfg); + hda_calculate_ssp_regs(ctx, dai_config, + ®s[REGS_OFFSET_CPR_BLOB]); + } + + dev_dbg(ctx->dev, "Mconfig for widget %s AFTER updation\n", w->name); + hda_dump_mconfig(ctx, m_cfg); +} + static int hda_sst_get_pipe_widget(struct device *dev, struct snd_soc_dapm_widget *w, struct ssth_pipe *pipe) { @@ -261,6 +472,7 @@ static int hda_init_pipe_modules(struct ssth_lib *ctx, mconfig = w->priv; /*TODO if loadable module, mconfig->is_loadable, load module */ + hda_sst_configure_widget(w, ctx, pinfo); ret = ssth_init_module(ctx, mconfig, NULL); if (ret < 0) return ret; @@ -619,7 +831,6 @@ void hda_sst_set_copier_dma_id(struct snd_soc_dai *dai, int dma_id, int stream, mconfig = hda_sst_get_module(dai, stream, is_fe, "cpr"); if (mconfig != NULL) mconfig->dma_id = dma_id; - return; } /*set BE copier I2s,DMIC, SLIMBUS config*/ diff --git a/sound/soc/hda/hda_dsp_ssp_config.c b/sound/soc/hda/hda_dsp_ssp_config.c index 8b79777fb8be..aa9d5542dc59 100644 --- a/sound/soc/hda/hda_dsp_ssp_config.c +++ b/sound/soc/hda/hda_dsp_ssp_config.c @@ -18,9 +18,14 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * */ + +#include +#include +#include "hda_dsp_controls.h" #include "hda_dsp_ssp_config.h" #include "hda_skl.h" + #define HDA_SSP_MAX_FREQ_192 19200000 struct hda_ssp_regs { @@ -128,8 +133,8 @@ static void azx_set_default_ssp_regs_v1(struct hda_ssp_regs *regs) } -static void azx_print_ssp_regs(struct sst_dsp_ctx *ctx, - struct hda_ssp_regs *regs) +static void azx_print_ssp_regs(struct ssth_lib *ctx, + struct hda_ssp_regs *regs) { dev_dbg(ctx->dev, "ssc0\t\t %x\n", regs->hda_ssc0); dev_dbg(ctx->dev, "ssc1\t\t %x\n", regs->hda_ssc1); @@ -143,7 +148,7 @@ static void azx_print_ssp_regs(struct sst_dsp_ctx *ctx, dev_dbg(ctx->dev, "ssioc\t\t %x\n", regs->hda_ssioc); } -static int azx_find_ssp_clk_divisor(struct sst_dsp_ctx *ctx, int fs, +static int azx_find_ssp_clk_divisor(struct ssth_lib *ctx, int fs, int slots, int s_fmt, int *div, int *dummy_bits) { int divisor, mod; @@ -190,7 +195,7 @@ static int azx_find_ssp_clk_divisor(struct sst_dsp_ctx *ctx, int fs, return -EINVAL; } -int azx_calculate_ssp_regs(struct sst_dsp_ctx *ctx, struct azx_dai_config *cfg, +int hda_calculate_ssp_regs(struct ssth_lib *ctx, struct hda_dai_config *cfg, void *ssp_regs) { struct hda_ssp_regs regs; @@ -198,7 +203,7 @@ int azx_calculate_ssp_regs(struct sst_dsp_ctx *ctx, struct azx_dai_config *cfg, int div, dummy; int dss, edss; int edmystop, dmystop; - struct azx_ssp_dai_config *ssp_cfg = &cfg->ssp_dai_config; + struct hda_ssp_dai_config *ssp_cfg = &cfg->ssp_dai_config; azx_set_default_ssp_regs_v1(®s); dev_dbg(ctx->dev, "Default value of registers set to:\n"); diff --git a/sound/soc/hda/hda_skl.h b/sound/soc/hda/hda_skl.h index f6d9c629a8e3..fd09bb855af6 100644 --- a/sound/soc/hda/hda_skl.h +++ b/sound/soc/hda/hda_skl.h @@ -8,6 +8,12 @@ #define HDA_SKL_SUSPEND_DELAY 2000 +#define HDA_SSP_MODE_I2S 0 +#define HDA_SSP_MODE_DSP_A 1 +#define HDA_SSP_MODE_DSP_B 2 +#define HDA_SSP_MAX_SLOTS 8 +#define HDA_DAI_TYPE_SSP 1 + struct hda_soc_bus { struct hdac_bus chip; struct device *dev; @@ -39,6 +45,73 @@ struct hda_platform_info { struct ssth_dsp_resource resource; struct list_head ppl_list; struct list_head ppl_start_list; + /* Structure to save dai_configuration, private data for each DAIs + * Memory will be allcated where platform driver is registered, based + * on number of DAIs getting registered. + */ + struct hda_dai_config *dai_config; +}; + +/*** + * struct soc_hda_ssp_dai_config - DAI configuration structure. SSP type of DAI + * configuration. Configuration specific to SSP DAIs will go here. + * + * @slot_width : * Number of slots per frame for tdm/pcm mode, + * for I2S mode this is dont care. Currently slot_width + * supported is same as active bits in slots. All dummy + * bits will be programmed after the last slot in TDM mode + * @slots : Number of slots per frame for tdm/pcm mode, + * for I2S mode this is dont care. Currently slot_width + * supported is same as active bits in slots. All dummy + * bits will be programmed after the last slot in TDM mode + * + * @ssp_mode : SP mode like DSP_A, I2S etc + * @tx_slot_mask: Indicates which tx slot active + * @rx_slot_mask: Indicates which rx slot active + * @bclk_invert : Clock invert, + * clock_invert = 1, data driven on rising edge of clock, + * sample on falling edge of clock. + * clock_invert = 0, data driver on falling edge of clock, + * sample on rising edge of clock. + * + * @fs_invert : Invert the frame sync, + * fs_invert = 0, frame sync active low + * fs_invert = 1, frame sync active high + * + * @fs_slave : Frame sync is slave or master 1 = slave, 0 = master + * @bclk_slave : BCLK is master of slave 1 = slave, 0 = master + * @i2s_instance: It its SSP dai, hardware I2S instance for this DAI + */ +struct hda_ssp_dai_config { + u8 slot_width; + u8 slots; + u8 ssp_mode; + u8 tx_slot_mask; + u8 rx_slot_mask; + bool bclk_invert; + bool fs_invert; + bool fs_slave; + bool bclk_slave; + u32 i2s_instance; +}; + +/*** + * struct soc_hda_dai_config - DAI configuration structure. DSP widgets and + * SSP registers will be configured based on this structure. This + * structure will be filled in part based on number of call to DAI methods + * like hw_params, set_tdm_slot and set_fmt. + * @s_fmt: Sampling format likt 24bit per ch, 16 bits per ch + * @num_channels : number of active channels. This must be 2 for I2S mode + * @sampling_rate : Sampling frequency in hertz 48000 for 48K sampling freq + * @dai_type : if its a SSP Dai, need to configure somethings extra for SSP dai + * @ssp_dai_config: Configuration specific to SSP dai + */ +struct hda_dai_config { + u8 s_fmt; + u8 num_channels; + u32 sampling_rate; + u32 dai_type; + struct hda_ssp_dai_config ssp_dai_config; }; int azx_get_delay_from_lpib(struct hdac_bus *chip, @@ -48,4 +121,6 @@ void azx_position_check(struct hdac_bus *chip, struct hdac_stream *azx_dev); int soc_hda_platform_unregister(struct device *dev); int soc_hda_platform_register(struct device *dev); +int hda_calculate_ssp_regs(struct ssth_lib *ctx, + struct hda_dai_config *cfg, void *ssp_regs); #endif /* __SOUND_SOC_HDA_SKL_H */