mirror of https://gitee.com/openkylin/linux.git
Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
This commit is contained in:
commit
7e9a8a8785
|
@ -222,6 +222,17 @@
|
|||
* %SKL_TKN_MM_U32_NUM_IN_FMT: Number of input formats
|
||||
* %SKL_TKN_MM_U32_NUM_OUT_FMT: Number of output formats
|
||||
*
|
||||
* %SKL_TKN_U32_ASTATE_IDX: Table Index for the A-State entry to be filled
|
||||
* with kcps and clock source
|
||||
*
|
||||
* %SKL_TKN_U32_ASTATE_COUNT: Number of valid entries in A-State table
|
||||
*
|
||||
* %SKL_TKN_U32_ASTATE_KCPS: Specifies the core load threshold (in kilo
|
||||
* cycles per second) below which DSP is clocked
|
||||
* from source specified by clock source.
|
||||
*
|
||||
* %SKL_TKN_U32_ASTATE_CLK_SRC: Clock source for A-State entry
|
||||
*
|
||||
* module_id and loadable flags dont have tokens as these values will be
|
||||
* read from the DSP FW manifest
|
||||
*
|
||||
|
@ -309,7 +320,11 @@ enum SKL_TKNS {
|
|||
SKL_TKN_MM_U32_NUM_IN_FMT,
|
||||
SKL_TKN_MM_U32_NUM_OUT_FMT,
|
||||
|
||||
SKL_TKN_MAX = SKL_TKN_MM_U32_NUM_OUT_FMT,
|
||||
SKL_TKN_U32_ASTATE_IDX,
|
||||
SKL_TKN_U32_ASTATE_COUNT,
|
||||
SKL_TKN_U32_ASTATE_KCPS,
|
||||
SKL_TKN_U32_ASTATE_CLK_SRC,
|
||||
SKL_TKN_MAX = SKL_TKN_U32_ASTATE_CLK_SRC,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -236,6 +236,9 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
|
|||
/* Find the IRQ */
|
||||
ctx->irq_num = platform_get_irq(pdev,
|
||||
ctx->pdata->res_info->acpi_ipc_irq_index);
|
||||
if (ctx->irq_num <= 0)
|
||||
return ctx->irq_num < 0 ? ctx->irq_num : -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ enum {
|
|||
BYT_RT5651_DMIC_MAP,
|
||||
BYT_RT5651_IN1_MAP,
|
||||
BYT_RT5651_IN2_MAP,
|
||||
BYT_RT5651_IN1_IN2_MAP,
|
||||
};
|
||||
|
||||
#define BYT_RT5651_MAP(quirk) ((quirk) & GENMASK(7, 0))
|
||||
|
@ -171,6 +172,13 @@ static const struct snd_soc_dapm_route byt_rt5651_intmic_in2_map[] = {
|
|||
{"IN2P", NULL, "Internal Mic"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_in2_map[] = {
|
||||
{"Internal Mic", NULL, "micbias1"},
|
||||
{"IN1P", NULL, "Internal Mic"},
|
||||
{"IN2P", NULL, "Internal Mic"},
|
||||
{"IN3P", NULL, "Headset Mic"},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new byt_rt5651_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Headphone"),
|
||||
SOC_DAPM_PIN_SWITCH("Headset Mic"),
|
||||
|
@ -256,7 +264,7 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
|
|||
DMI_MATCH(DMI_SYS_VENDOR, "KIANO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "KIANO SlimNote 14.2"),
|
||||
},
|
||||
.driver_data = (void *)(BYT_RT5651_IN2_MAP),
|
||||
.driver_data = (void *)(BYT_RT5651_IN1_IN2_MAP),
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
@ -281,6 +289,10 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
|
|||
custom_map = byt_rt5651_intmic_in2_map;
|
||||
num_routes = ARRAY_SIZE(byt_rt5651_intmic_in2_map);
|
||||
break;
|
||||
case BYT_RT5651_IN1_IN2_MAP:
|
||||
custom_map = byt_rt5651_intmic_in1_in2_map;
|
||||
num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_in2_map);
|
||||
break;
|
||||
default:
|
||||
custom_map = byt_rt5651_intmic_dmic_map;
|
||||
num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic_map);
|
||||
|
|
|
@ -76,7 +76,7 @@ static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream,
|
|||
}
|
||||
|
||||
/* set correct codec filter for DAI format and clock config */
|
||||
snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000);
|
||||
snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -225,7 +225,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
|
|||
}
|
||||
|
||||
jack = &ctx->kabylake_headset;
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
|
||||
|
|
|
@ -195,7 +195,7 @@ static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd)
|
|||
}
|
||||
|
||||
jack = &ctx->kabylake_headset;
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
|
||||
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
|
||||
|
|
|
@ -372,6 +372,8 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
|
|||
|
||||
/* retrive the irq number */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq <= 0)
|
||||
return irq < 0 ? irq : -ENODEV;
|
||||
|
||||
/* audio interrupt base of SRAM location where
|
||||
* interrupts are stored by System FW */
|
||||
|
|
|
@ -269,7 +269,7 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
|
|||
*/
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(time);
|
||||
while (((sst_dsp_shim_read_unlocked(ctx, offset) & mask) != target)
|
||||
while ((((reg = sst_dsp_shim_read_unlocked(ctx, offset)) & mask) != target)
|
||||
&& time_before(jiffies, timeout)) {
|
||||
k++;
|
||||
if (k > 10)
|
||||
|
@ -278,8 +278,6 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask,
|
|||
usleep_range(s, 2*s);
|
||||
}
|
||||
|
||||
reg = sst_dsp_shim_read_unlocked(ctx, offset);
|
||||
|
||||
if ((reg & mask) == target) {
|
||||
dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n",
|
||||
reg, operation);
|
||||
|
|
|
@ -595,7 +595,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
|||
INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3);
|
||||
skl->d0i3.state = SKL_DSP_D0I3_NONE;
|
||||
|
||||
return 0;
|
||||
return skl_dsp_acquire_irq(sst);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bxt_sst_dsp_init);
|
||||
|
||||
|
|
|
@ -458,7 +458,7 @@ int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
|||
cnl->boot_complete = false;
|
||||
init_waitqueue_head(&cnl->boot_wait);
|
||||
|
||||
return 0;
|
||||
return skl_dsp_acquire_irq(sst);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cnl_sst_dsp_init);
|
||||
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* skl-i2s.h - i2s blob mapping
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corp
|
||||
* Author: Subhransu S. Prusty < subhransu.s.prusty@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 published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_SOC_SKL_I2S_H
|
||||
#define __SOUND_SOC_SKL_I2S_H
|
||||
|
||||
#define SKL_I2S_MAX_TIME_SLOTS 8
|
||||
#define SKL_MCLK_DIV_CLK_SRC_MASK GENMASK(17, 16)
|
||||
|
||||
#define SKL_MNDSS_DIV_CLK_SRC_MASK GENMASK(21, 20)
|
||||
#define SKL_SHIFT(x) (ffs(x) - 1)
|
||||
#define SKL_MCLK_DIV_RATIO_MASK GENMASK(11, 0)
|
||||
|
||||
struct skl_i2s_config {
|
||||
u32 ssc0;
|
||||
u32 ssc1;
|
||||
u32 sscto;
|
||||
u32 sspsp;
|
||||
u32 sstsa;
|
||||
u32 ssrsa;
|
||||
u32 ssc2;
|
||||
u32 sspsp2;
|
||||
u32 ssc3;
|
||||
u32 ssioc;
|
||||
} __packed;
|
||||
|
||||
struct skl_i2s_config_mclk {
|
||||
u32 mdivctrl;
|
||||
u32 mdivr;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct skl_i2s_config_blob_legacy - Structure defines I2S Gateway
|
||||
* configuration legacy blob
|
||||
*
|
||||
* @gtw_attr: Gateway attribute for the I2S Gateway
|
||||
* @tdm_ts_group: TDM slot mapping against channels in the Gateway.
|
||||
* @i2s_cfg: I2S HW registers
|
||||
* @mclk: MCLK clock source and divider values
|
||||
*/
|
||||
struct skl_i2s_config_blob_legacy {
|
||||
u32 gtw_attr;
|
||||
u32 tdm_ts_group[SKL_I2S_MAX_TIME_SLOTS];
|
||||
struct skl_i2s_config i2s_cfg;
|
||||
struct skl_i2s_config_mclk mclk;
|
||||
};
|
||||
|
||||
#endif /* __SOUND_SOC_SKL_I2S_H */
|
|
@ -55,6 +55,19 @@ static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define SKL_ASTATE_PARAM_ID 4
|
||||
|
||||
void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data)
|
||||
{
|
||||
struct skl_ipc_large_config_msg msg = {0};
|
||||
|
||||
msg.large_param_id = SKL_ASTATE_PARAM_ID;
|
||||
msg.param_data_size = (cnt * sizeof(struct skl_astate_param) +
|
||||
sizeof(cnt));
|
||||
|
||||
skl_ipc_set_large_config(&ctx->ipc, &msg, data);
|
||||
}
|
||||
|
||||
#define NOTIFICATION_PARAM_ID 3
|
||||
#define NOTIFICATION_MASK 0xf
|
||||
|
||||
|
@ -404,11 +417,20 @@ int skl_resume_dsp(struct skl *skl)
|
|||
if (skl->skl_sst->is_first_boot == true)
|
||||
return 0;
|
||||
|
||||
/* disable dynamic clock gating during fw and lib download */
|
||||
ctx->enable_miscbdcge(ctx->dev, false);
|
||||
|
||||
ret = skl_dsp_wake(ctx->dsp);
|
||||
ctx->enable_miscbdcge(ctx->dev, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
skl_dsp_enable_notification(skl->skl_sst, false);
|
||||
|
||||
if (skl->cfg.astate_cfg != NULL) {
|
||||
skl_dsp_set_astate_cfg(skl->skl_sst, skl->cfg.astate_cfg->count,
|
||||
skl->cfg.astate_cfg);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
#include <linux/pci.h>
|
||||
#include "skl.h"
|
||||
#include "skl-i2s.h"
|
||||
|
||||
#define NHLT_ACPI_HEADER_SIG "NHLT"
|
||||
|
||||
|
@ -277,3 +278,157 @@ void skl_nhlt_remove_sysfs(struct skl *skl)
|
|||
|
||||
sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Queries NHLT for all the fmt configuration for a particular endpoint and
|
||||
* stores all possible rates supported in a rate table for the corresponding
|
||||
* sclk/sclkfs.
|
||||
*/
|
||||
static void skl_get_ssp_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks,
|
||||
struct nhlt_fmt *fmt, u8 id)
|
||||
{
|
||||
struct skl_i2s_config_blob_legacy *i2s_config;
|
||||
struct skl_clk_parent_src *parent;
|
||||
struct skl_ssp_clk *sclk, *sclkfs;
|
||||
struct nhlt_fmt_cfg *fmt_cfg;
|
||||
struct wav_fmt_ext *wav_fmt;
|
||||
unsigned long rate = 0;
|
||||
bool present = false;
|
||||
int rate_index = 0;
|
||||
u16 channels, bps;
|
||||
u8 clk_src;
|
||||
int i, j;
|
||||
u32 fs;
|
||||
|
||||
sclk = &ssp_clks[SKL_SCLK_OFS];
|
||||
sclkfs = &ssp_clks[SKL_SCLKFS_OFS];
|
||||
|
||||
if (fmt->fmt_count == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < fmt->fmt_count; i++) {
|
||||
fmt_cfg = &fmt->fmt_config[i];
|
||||
wav_fmt = &fmt_cfg->fmt_ext;
|
||||
|
||||
channels = wav_fmt->fmt.channels;
|
||||
bps = wav_fmt->fmt.bits_per_sample;
|
||||
fs = wav_fmt->fmt.samples_per_sec;
|
||||
|
||||
/*
|
||||
* In case of TDM configuration on a ssp, there can
|
||||
* be more than one blob in which channel masks are
|
||||
* different for each usecase for a specific rate and bps.
|
||||
* But the sclk rate will be generated for the total
|
||||
* number of channels used for that endpoint.
|
||||
*
|
||||
* So for the given fs and bps, choose blob which has
|
||||
* the superset of all channels for that endpoint and
|
||||
* derive the rate.
|
||||
*/
|
||||
for (j = i; j < fmt->fmt_count; j++) {
|
||||
fmt_cfg = &fmt->fmt_config[j];
|
||||
wav_fmt = &fmt_cfg->fmt_ext;
|
||||
if ((fs == wav_fmt->fmt.samples_per_sec) &&
|
||||
(bps == wav_fmt->fmt.bits_per_sample))
|
||||
channels = max_t(u16, channels,
|
||||
wav_fmt->fmt.channels);
|
||||
}
|
||||
|
||||
rate = channels * bps * fs;
|
||||
|
||||
/* check if the rate is added already to the given SSP's sclk */
|
||||
for (j = 0; (j < SKL_MAX_CLK_RATES) &&
|
||||
(sclk[id].rate_cfg[j].rate != 0); j++) {
|
||||
if (sclk[id].rate_cfg[j].rate == rate) {
|
||||
present = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill rate and parent for sclk/sclkfs */
|
||||
if (!present) {
|
||||
/* MCLK Divider Source Select */
|
||||
i2s_config = (struct skl_i2s_config_blob_legacy *)
|
||||
fmt->fmt_config[0].config.caps;
|
||||
clk_src = ((i2s_config->mclk.mdivctrl)
|
||||
& SKL_MNDSS_DIV_CLK_SRC_MASK) >>
|
||||
SKL_SHIFT(SKL_MNDSS_DIV_CLK_SRC_MASK);
|
||||
|
||||
parent = skl_get_parent_clk(clk_src);
|
||||
|
||||
/*
|
||||
* Do not copy the config data if there is no parent
|
||||
* clock available for this clock source select
|
||||
*/
|
||||
if (!parent)
|
||||
continue;
|
||||
|
||||
sclk[id].rate_cfg[rate_index].rate = rate;
|
||||
sclk[id].rate_cfg[rate_index].config = fmt_cfg;
|
||||
sclkfs[id].rate_cfg[rate_index].rate = rate;
|
||||
sclkfs[id].rate_cfg[rate_index].config = fmt_cfg;
|
||||
sclk[id].parent_name = parent->name;
|
||||
sclkfs[id].parent_name = parent->name;
|
||||
|
||||
rate_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void skl_get_mclk(struct skl *skl, struct skl_ssp_clk *mclk,
|
||||
struct nhlt_fmt *fmt, u8 id)
|
||||
{
|
||||
struct skl_i2s_config_blob_legacy *i2s_config;
|
||||
struct nhlt_specific_cfg *fmt_cfg;
|
||||
struct skl_clk_parent_src *parent;
|
||||
u32 clkdiv, div_ratio;
|
||||
u8 clk_src;
|
||||
|
||||
fmt_cfg = &fmt->fmt_config[0].config;
|
||||
i2s_config = (struct skl_i2s_config_blob_legacy *)fmt_cfg->caps;
|
||||
|
||||
/* MCLK Divider Source Select */
|
||||
clk_src = ((i2s_config->mclk.mdivctrl) & SKL_MCLK_DIV_CLK_SRC_MASK) >>
|
||||
SKL_SHIFT(SKL_MCLK_DIV_CLK_SRC_MASK);
|
||||
|
||||
clkdiv = i2s_config->mclk.mdivr & SKL_MCLK_DIV_RATIO_MASK;
|
||||
|
||||
/* bypass divider */
|
||||
div_ratio = 1;
|
||||
|
||||
if (clkdiv != SKL_MCLK_DIV_RATIO_MASK)
|
||||
/* Divider is 2 + clkdiv */
|
||||
div_ratio = clkdiv + 2;
|
||||
|
||||
/* Calculate MCLK rate from source using div value */
|
||||
parent = skl_get_parent_clk(clk_src);
|
||||
if (!parent)
|
||||
return;
|
||||
|
||||
mclk[id].rate_cfg[0].rate = parent->rate/div_ratio;
|
||||
mclk[id].rate_cfg[0].config = &fmt->fmt_config[0];
|
||||
mclk[id].parent_name = parent->name;
|
||||
}
|
||||
|
||||
void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks)
|
||||
{
|
||||
struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
|
||||
struct nhlt_endpoint *epnt;
|
||||
struct nhlt_fmt *fmt;
|
||||
int i;
|
||||
u8 id;
|
||||
|
||||
epnt = (struct nhlt_endpoint *)nhlt->desc;
|
||||
for (i = 0; i < nhlt->endpoint_count; i++) {
|
||||
if (epnt->linktype == NHLT_LINK_SSP) {
|
||||
id = epnt->virtual_bus_id;
|
||||
|
||||
fmt = (struct nhlt_fmt *)(epnt->config.caps
|
||||
+ epnt->config.size);
|
||||
|
||||
skl_get_ssp_clks(skl, ssp_clks, fmt, id);
|
||||
skl_get_mclk(skl, ssp_clks, fmt, id);
|
||||
}
|
||||
epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -537,7 +537,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
|
||||
|
||||
link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
|
||||
link = snd_hdac_ext_bus_get_link(ebus, codec_dai->component->name);
|
||||
if (!link)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -620,7 +620,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
|
|||
|
||||
link_dev->link_prepared = 0;
|
||||
|
||||
link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name);
|
||||
link = snd_hdac_ext_bus_get_link(ebus, rtd->codec_dai->component->name);
|
||||
if (!link)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -1343,7 +1343,11 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
/* disable dynamic clock gating during fw and lib download */
|
||||
skl->skl_sst->enable_miscbdcge(platform->dev, false);
|
||||
|
||||
ret = ops->init_fw(platform->dev, skl->skl_sst);
|
||||
skl->skl_sst->enable_miscbdcge(platform->dev, true);
|
||||
if (ret < 0) {
|
||||
dev_err(platform->dev, "Failed to boot first fw: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -1351,6 +1355,12 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform)
|
|||
skl_populate_modules(skl);
|
||||
skl->skl_sst->update_d0i3c = skl_update_d0i3c;
|
||||
skl_dsp_enable_notification(skl->skl_sst, false);
|
||||
|
||||
if (skl->cfg.astate_cfg != NULL) {
|
||||
skl_dsp_set_astate_cfg(skl->skl_sst,
|
||||
skl->cfg.astate_cfg->count,
|
||||
skl->cfg.astate_cfg);
|
||||
}
|
||||
}
|
||||
pm_runtime_mark_last_busy(platform->dev);
|
||||
pm_runtime_put_autosuspend(platform->dev);
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* skl-ssp-clk.h - Skylake ssp clock information and ipc structure
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corp
|
||||
* Author: Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com>
|
||||
* Author: Subhransu S. Prusty <subhransu.s.prusty@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 published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SOUND_SOC_SKL_SSP_CLK_H
|
||||
#define SOUND_SOC_SKL_SSP_CLK_H
|
||||
|
||||
#define SKL_MAX_SSP 6
|
||||
/* xtal/cardinal/pll, parent of ssp clocks and mclk */
|
||||
#define SKL_MAX_CLK_SRC 3
|
||||
#define SKL_MAX_SSP_CLK_TYPES 3 /* mclk, sclk, sclkfs */
|
||||
|
||||
#define SKL_MAX_CLK_CNT (SKL_MAX_SSP * SKL_MAX_SSP_CLK_TYPES)
|
||||
|
||||
/* Max number of configurations supported for each clock */
|
||||
#define SKL_MAX_CLK_RATES 10
|
||||
|
||||
#define SKL_SCLK_OFS SKL_MAX_SSP
|
||||
#define SKL_SCLKFS_OFS (SKL_SCLK_OFS + SKL_MAX_SSP)
|
||||
|
||||
enum skl_clk_type {
|
||||
SKL_MCLK,
|
||||
SKL_SCLK,
|
||||
SKL_SCLK_FS,
|
||||
};
|
||||
|
||||
enum skl_clk_src_type {
|
||||
SKL_XTAL,
|
||||
SKL_CARDINAL,
|
||||
SKL_PLL,
|
||||
};
|
||||
|
||||
struct skl_clk_parent_src {
|
||||
u8 clk_id;
|
||||
const char *name;
|
||||
unsigned long rate;
|
||||
const char *parent_name;
|
||||
};
|
||||
|
||||
struct skl_clk_rate_cfg_table {
|
||||
unsigned long rate;
|
||||
void *config;
|
||||
};
|
||||
|
||||
/*
|
||||
* rate for mclk will be in rates[0]. For sclk and sclkfs, rates[] store
|
||||
* all possible clocks ssp can generate for that platform.
|
||||
*/
|
||||
struct skl_ssp_clk {
|
||||
const char *name;
|
||||
const char *parent_name;
|
||||
struct skl_clk_rate_cfg_table rate_cfg[SKL_MAX_CLK_RATES];
|
||||
};
|
||||
|
||||
struct skl_clk_pdata {
|
||||
struct skl_clk_parent_src *parent_clks;
|
||||
int num_clks;
|
||||
struct skl_ssp_clk *ssp_clks;
|
||||
void *pvt_data;
|
||||
};
|
||||
|
||||
#endif /* SOUND_SOC_SKL_SSP_CLK_H */
|
|
@ -435,16 +435,22 @@ struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return sst;
|
||||
}
|
||||
|
||||
int skl_dsp_acquire_irq(struct sst_dsp *sst)
|
||||
{
|
||||
struct sst_dsp_device *sst_dev = sst->sst_dev;
|
||||
int ret;
|
||||
|
||||
/* Register the ISR */
|
||||
ret = request_threaded_irq(sst->irq, sst->ops->irq_handler,
|
||||
sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n",
|
||||
sst->irq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sst;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void skl_dsp_free(struct sst_dsp *dsp)
|
||||
|
|
|
@ -206,6 +206,7 @@ int skl_cldma_wait_interruptible(struct sst_dsp *ctx);
|
|||
void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state);
|
||||
struct sst_dsp *skl_dsp_ctx_init(struct device *dev,
|
||||
struct sst_dsp_device *sst_dev, int irq);
|
||||
int skl_dsp_acquire_irq(struct sst_dsp *sst);
|
||||
bool is_skl_dsp_running(struct sst_dsp *ctx);
|
||||
|
||||
unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx);
|
||||
|
@ -251,6 +252,9 @@ void skl_freeup_uuid_list(struct skl_sst *ctx);
|
|||
|
||||
int skl_dsp_strip_extended_manifest(struct firmware *fw);
|
||||
void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable);
|
||||
|
||||
void skl_dsp_set_astate_cfg(struct skl_sst *ctx, u32 cnt, void *data);
|
||||
|
||||
int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name,
|
||||
struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp,
|
||||
struct sst_dsp_device *skl_dev);
|
||||
|
|
|
@ -178,7 +178,8 @@ static inline int skl_pvtid_128(struct uuid_module *module)
|
|||
* skl_get_pvt_id: generate a private id for use as module id
|
||||
*
|
||||
* @ctx: driver context
|
||||
* @mconfig: module configuration data
|
||||
* @uuid_mod: module's uuid
|
||||
* @instance_id: module's instance id
|
||||
*
|
||||
* This generates a 128 bit private unique id for a module TYPE so that
|
||||
* module instance is unique
|
||||
|
@ -208,7 +209,8 @@ EXPORT_SYMBOL_GPL(skl_get_pvt_id);
|
|||
* skl_put_pvt_id: free up the private id allocated
|
||||
*
|
||||
* @ctx: driver context
|
||||
* @mconfig: module configuration data
|
||||
* @uuid_mod: module's uuid
|
||||
* @pvt_id: module pvt id
|
||||
*
|
||||
* This frees a 128 bit private unique id previously generated
|
||||
*/
|
||||
|
|
|
@ -569,7 +569,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
|
|||
|
||||
sst->fw_ops = skl_fw_ops;
|
||||
|
||||
return 0;
|
||||
return skl_dsp_acquire_irq(sst);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
|
||||
|
||||
|
|
|
@ -3056,11 +3056,13 @@ static int skl_tplg_get_int_tkn(struct device *dev,
|
|||
struct snd_soc_tplg_vendor_value_elem *tkn_elem,
|
||||
struct skl *skl)
|
||||
{
|
||||
int tkn_count = 0, ret;
|
||||
int tkn_count = 0, ret, size;
|
||||
static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx;
|
||||
struct skl_module_res *res = NULL;
|
||||
struct skl_module_iface *fmt = NULL;
|
||||
struct skl_module *mod = NULL;
|
||||
static struct skl_astate_param *astate_table;
|
||||
static int astate_cfg_idx, count;
|
||||
int i;
|
||||
|
||||
if (skl->modules) {
|
||||
|
@ -3093,6 +3095,46 @@ static int skl_tplg_get_int_tkn(struct device *dev,
|
|||
mod_idx = tkn_elem->value;
|
||||
break;
|
||||
|
||||
case SKL_TKN_U32_ASTATE_COUNT:
|
||||
if (astate_table != NULL) {
|
||||
dev_err(dev, "More than one entry for A-State count");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tkn_elem->value > SKL_MAX_ASTATE_CFG) {
|
||||
dev_err(dev, "Invalid A-State count %d\n",
|
||||
tkn_elem->value);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size = tkn_elem->value * sizeof(struct skl_astate_param) +
|
||||
sizeof(count);
|
||||
skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL);
|
||||
if (!skl->cfg.astate_cfg)
|
||||
return -ENOMEM;
|
||||
|
||||
astate_table = skl->cfg.astate_cfg->astate_table;
|
||||
count = skl->cfg.astate_cfg->count = tkn_elem->value;
|
||||
break;
|
||||
|
||||
case SKL_TKN_U32_ASTATE_IDX:
|
||||
if (tkn_elem->value >= count) {
|
||||
dev_err(dev, "Invalid A-State index %d\n",
|
||||
tkn_elem->value);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
astate_cfg_idx = tkn_elem->value;
|
||||
break;
|
||||
|
||||
case SKL_TKN_U32_ASTATE_KCPS:
|
||||
astate_table[astate_cfg_idx].kcps = tkn_elem->value;
|
||||
break;
|
||||
|
||||
case SKL_TKN_U32_ASTATE_CLK_SRC:
|
||||
astate_table[astate_cfg_idx].clk_src = tkn_elem->value;
|
||||
break;
|
||||
|
||||
case SKL_TKN_U8_IN_PIN_TYPE:
|
||||
case SKL_TKN_U8_OUT_PIN_TYPE:
|
||||
case SKL_TKN_U8_IN_QUEUE_COUNT:
|
||||
|
|
|
@ -355,6 +355,7 @@ static int skl_resume(struct device *dev)
|
|||
|
||||
if (ebus->cmd_dma_state)
|
||||
snd_hdac_bus_init_cmd_io(&ebus->bus);
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = _skl_resume(ebus);
|
||||
|
||||
|
@ -435,19 +436,51 @@ static int skl_free(struct hdac_ext_bus *ebus)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int skl_machine_device_register(struct skl *skl, void *driver_data)
|
||||
/*
|
||||
* For each ssp there are 3 clocks (mclk/sclk/sclkfs).
|
||||
* e.g. for ssp0, clocks will be named as
|
||||
* "ssp0_mclk", "ssp0_sclk", "ssp0_sclkfs"
|
||||
* So for skl+, there are 6 ssps, so 18 clocks will be created.
|
||||
*/
|
||||
static struct skl_ssp_clk skl_ssp_clks[] = {
|
||||
{.name = "ssp0_mclk"}, {.name = "ssp1_mclk"}, {.name = "ssp2_mclk"},
|
||||
{.name = "ssp3_mclk"}, {.name = "ssp4_mclk"}, {.name = "ssp5_mclk"},
|
||||
{.name = "ssp0_sclk"}, {.name = "ssp1_sclk"}, {.name = "ssp2_sclk"},
|
||||
{.name = "ssp3_sclk"}, {.name = "ssp4_sclk"}, {.name = "ssp5_sclk"},
|
||||
{.name = "ssp0_sclkfs"}, {.name = "ssp1_sclkfs"},
|
||||
{.name = "ssp2_sclkfs"},
|
||||
{.name = "ssp3_sclkfs"}, {.name = "ssp4_sclkfs"},
|
||||
{.name = "ssp5_sclkfs"},
|
||||
};
|
||||
|
||||
static int skl_find_machine(struct skl *skl, void *driver_data)
|
||||
{
|
||||
struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
|
||||
struct platform_device *pdev;
|
||||
struct snd_soc_acpi_mach *mach = driver_data;
|
||||
int ret;
|
||||
struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
|
||||
struct skl_machine_pdata *pdata;
|
||||
|
||||
mach = snd_soc_acpi_find_machine(mach);
|
||||
if (mach == NULL) {
|
||||
dev_err(bus->dev, "No matching machine driver found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
skl->mach = mach;
|
||||
skl->fw_name = mach->fw_filename;
|
||||
pdata = skl->mach->pdata;
|
||||
|
||||
if (mach->pdata)
|
||||
skl->use_tplg_pcm = pdata->use_tplg_pcm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int skl_machine_device_register(struct skl *skl)
|
||||
{
|
||||
struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
|
||||
struct snd_soc_acpi_mach *mach = skl->mach;
|
||||
struct platform_device *pdev;
|
||||
int ret;
|
||||
|
||||
pdev = platform_device_alloc(mach->drv_name, -1);
|
||||
if (pdev == NULL) {
|
||||
|
@ -462,11 +495,8 @@ static int skl_machine_device_register(struct skl *skl, void *driver_data)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (mach->pdata) {
|
||||
skl->use_tplg_pcm =
|
||||
((struct skl_machine_pdata *)mach->pdata)->use_tplg_pcm;
|
||||
if (mach->pdata)
|
||||
dev_set_drvdata(&pdev->dev, mach->pdata);
|
||||
}
|
||||
|
||||
skl->i2s_dev = pdev;
|
||||
|
||||
|
@ -509,6 +539,74 @@ static void skl_dmic_device_unregister(struct skl *skl)
|
|||
platform_device_unregister(skl->dmic_dev);
|
||||
}
|
||||
|
||||
static struct skl_clk_parent_src skl_clk_src[] = {
|
||||
{ .clk_id = SKL_XTAL, .name = "xtal" },
|
||||
{ .clk_id = SKL_CARDINAL, .name = "cardinal", .rate = 24576000 },
|
||||
{ .clk_id = SKL_PLL, .name = "pll", .rate = 96000000 },
|
||||
};
|
||||
|
||||
struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(skl_clk_src); i++) {
|
||||
if (skl_clk_src[i].clk_id == clk_id)
|
||||
return &skl_clk_src[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void init_skl_xtal_rate(int pci_id)
|
||||
{
|
||||
switch (pci_id) {
|
||||
case 0x9d70:
|
||||
case 0x9d71:
|
||||
skl_clk_src[0].rate = 24000000;
|
||||
return;
|
||||
|
||||
default:
|
||||
skl_clk_src[0].rate = 19200000;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int skl_clock_device_register(struct skl *skl)
|
||||
{
|
||||
struct platform_device_info pdevinfo = {NULL};
|
||||
struct skl_clk_pdata *clk_pdata;
|
||||
|
||||
clk_pdata = devm_kzalloc(&skl->pci->dev, sizeof(*clk_pdata),
|
||||
GFP_KERNEL);
|
||||
if (!clk_pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
init_skl_xtal_rate(skl->pci->device);
|
||||
|
||||
clk_pdata->parent_clks = skl_clk_src;
|
||||
clk_pdata->ssp_clks = skl_ssp_clks;
|
||||
clk_pdata->num_clks = ARRAY_SIZE(skl_ssp_clks);
|
||||
|
||||
/* Query NHLT to fill the rates and parent */
|
||||
skl_get_clks(skl, clk_pdata->ssp_clks);
|
||||
clk_pdata->pvt_data = skl;
|
||||
|
||||
/* Register Platform device */
|
||||
pdevinfo.parent = &skl->pci->dev;
|
||||
pdevinfo.id = -1;
|
||||
pdevinfo.name = "skl-ssp-clk";
|
||||
pdevinfo.data = clk_pdata;
|
||||
pdevinfo.size_data = sizeof(*clk_pdata);
|
||||
skl->clk_dev = platform_device_register_full(&pdevinfo);
|
||||
return PTR_ERR_OR_ZERO(skl->clk_dev);
|
||||
}
|
||||
|
||||
static void skl_clock_device_unregister(struct skl *skl)
|
||||
{
|
||||
if (skl->clk_dev)
|
||||
platform_device_unregister(skl->clk_dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe the given codec address
|
||||
*/
|
||||
|
@ -615,18 +713,30 @@ static void skl_probe_work(struct work_struct *work)
|
|||
/* create codec instances */
|
||||
skl_codec_create(ebus);
|
||||
|
||||
/* register platform dai and controls */
|
||||
err = skl_platform_register(bus->dev);
|
||||
if (err < 0) {
|
||||
dev_err(bus->dev, "platform register failed: %d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bus->ppcap) {
|
||||
err = skl_machine_device_register(skl);
|
||||
if (err < 0) {
|
||||
dev_err(bus->dev, "machine register failed: %d\n", err);
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) {
|
||||
err = snd_hdac_display_power(bus, false);
|
||||
if (err < 0) {
|
||||
dev_err(bus->dev, "Cannot turn off display power on i915\n");
|
||||
skl_machine_device_unregister(skl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* register platform dai and controls */
|
||||
err = skl_platform_register(bus->dev);
|
||||
if (err < 0)
|
||||
return;
|
||||
/*
|
||||
* we are done probing so decrement link counts
|
||||
*/
|
||||
|
@ -791,18 +901,21 @@ static int skl_probe(struct pci_dev *pci,
|
|||
|
||||
/* check if dsp is there */
|
||||
if (bus->ppcap) {
|
||||
err = skl_machine_device_register(skl,
|
||||
(void *)pci_id->driver_data);
|
||||
/* create device for dsp clk */
|
||||
err = skl_clock_device_register(skl);
|
||||
if (err < 0)
|
||||
goto out_clk_free;
|
||||
|
||||
err = skl_find_machine(skl, (void *)pci_id->driver_data);
|
||||
if (err < 0)
|
||||
goto out_nhlt_free;
|
||||
|
||||
err = skl_init_dsp(skl);
|
||||
if (err < 0) {
|
||||
dev_dbg(bus->dev, "error failed to register dsp\n");
|
||||
goto out_mach_free;
|
||||
goto out_nhlt_free;
|
||||
}
|
||||
skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge;
|
||||
|
||||
}
|
||||
if (bus->mlcap)
|
||||
snd_hdac_ext_bus_get_ml_capabilities(ebus);
|
||||
|
@ -820,8 +933,8 @@ static int skl_probe(struct pci_dev *pci,
|
|||
|
||||
out_dsp_free:
|
||||
skl_free_dsp(skl);
|
||||
out_mach_free:
|
||||
skl_machine_device_unregister(skl);
|
||||
out_clk_free:
|
||||
skl_clock_device_unregister(skl);
|
||||
out_nhlt_free:
|
||||
skl_nhlt_free(skl->nhlt);
|
||||
out_free:
|
||||
|
@ -872,6 +985,7 @@ static void skl_remove(struct pci_dev *pci)
|
|||
skl_free_dsp(skl);
|
||||
skl_machine_device_unregister(skl);
|
||||
skl_dmic_device_unregister(skl);
|
||||
skl_clock_device_unregister(skl);
|
||||
skl_nhlt_remove_sysfs(skl);
|
||||
skl_nhlt_free(skl->nhlt);
|
||||
skl_free(ebus);
|
||||
|
|
|
@ -25,9 +25,12 @@
|
|||
#include <sound/hdaudio_ext.h>
|
||||
#include <sound/soc.h>
|
||||
#include "skl-nhlt.h"
|
||||
#include "skl-ssp-clk.h"
|
||||
|
||||
#define SKL_SUSPEND_DELAY 2000
|
||||
|
||||
#define SKL_MAX_ASTATE_CFG 3
|
||||
|
||||
#define AZX_PCIREG_PGCTL 0x44
|
||||
#define AZX_PGCTL_LSRMD_MASK (1 << 4)
|
||||
#define AZX_PCIREG_CGCTL 0x48
|
||||
|
@ -45,6 +48,20 @@ struct skl_dsp_resource {
|
|||
|
||||
struct skl_debug;
|
||||
|
||||
struct skl_astate_param {
|
||||
u32 kcps;
|
||||
u32 clk_src;
|
||||
};
|
||||
|
||||
struct skl_astate_config {
|
||||
u32 count;
|
||||
struct skl_astate_param astate_table[0];
|
||||
};
|
||||
|
||||
struct skl_fw_config {
|
||||
struct skl_astate_config *astate_cfg;
|
||||
};
|
||||
|
||||
struct skl {
|
||||
struct hdac_ext_bus ebus;
|
||||
struct pci_dev *pci;
|
||||
|
@ -52,6 +69,7 @@ struct skl {
|
|||
unsigned int init_done:1; /* delayed init status */
|
||||
struct platform_device *dmic_dev;
|
||||
struct platform_device *i2s_dev;
|
||||
struct platform_device *clk_dev;
|
||||
struct snd_soc_platform *platform;
|
||||
struct snd_soc_dai_driver *dais;
|
||||
|
||||
|
@ -75,6 +93,8 @@ struct skl {
|
|||
u8 nr_modules;
|
||||
struct skl_module **modules;
|
||||
bool use_tplg_pcm;
|
||||
struct skl_fw_config cfg;
|
||||
struct snd_soc_acpi_mach *mach;
|
||||
};
|
||||
|
||||
#define skl_to_ebus(s) (&(s)->ebus)
|
||||
|
@ -125,6 +145,8 @@ const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id);
|
|||
void skl_update_d0i3c(struct device *dev, bool enable);
|
||||
int skl_nhlt_create_sysfs(struct skl *skl);
|
||||
void skl_nhlt_remove_sysfs(struct skl *skl);
|
||||
void skl_get_clks(struct skl *skl, struct skl_ssp_clk *ssp_clks);
|
||||
struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id);
|
||||
|
||||
struct skl_module_cfg;
|
||||
|
||||
|
|
Loading…
Reference in New Issue