You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge remote-tracking branches 'asoc/topic/hdmi', 'asoc/topic/intel', 'asoc/topic/jack', 'asoc/topic/jz4740' and 'asoc/topic/lm49453' into asoc-next
This commit is contained in:
@@ -16,6 +16,9 @@
|
||||
|
||||
#include <linux/sfi.h>
|
||||
|
||||
#define MAX_NUM_STREAMS_MRFLD 25
|
||||
#define MAX_NUM_STREAMS MAX_NUM_STREAMS_MRFLD
|
||||
|
||||
enum sst_audio_task_id_mrfld {
|
||||
SST_TASK_ID_NONE = 0,
|
||||
SST_TASK_ID_SBA = 1,
|
||||
@@ -73,6 +76,65 @@ struct sst_platform_data {
|
||||
unsigned int strm_map_size;
|
||||
};
|
||||
|
||||
struct sst_info {
|
||||
u32 iram_start;
|
||||
u32 iram_end;
|
||||
bool iram_use;
|
||||
u32 dram_start;
|
||||
u32 dram_end;
|
||||
bool dram_use;
|
||||
u32 imr_start;
|
||||
u32 imr_end;
|
||||
bool imr_use;
|
||||
u32 mailbox_start;
|
||||
bool use_elf;
|
||||
bool lpe_viewpt_rqd;
|
||||
unsigned int max_streams;
|
||||
u32 dma_max_len;
|
||||
u8 num_probes;
|
||||
};
|
||||
|
||||
struct sst_lib_dnld_info {
|
||||
unsigned int mod_base;
|
||||
unsigned int mod_end;
|
||||
unsigned int mod_table_offset;
|
||||
unsigned int mod_table_size;
|
||||
bool mod_ddr_dnld;
|
||||
};
|
||||
|
||||
struct sst_res_info {
|
||||
unsigned int shim_offset;
|
||||
unsigned int shim_size;
|
||||
unsigned int shim_phy_addr;
|
||||
unsigned int ssp0_offset;
|
||||
unsigned int ssp0_size;
|
||||
unsigned int dma0_offset;
|
||||
unsigned int dma0_size;
|
||||
unsigned int dma1_offset;
|
||||
unsigned int dma1_size;
|
||||
unsigned int iram_offset;
|
||||
unsigned int iram_size;
|
||||
unsigned int dram_offset;
|
||||
unsigned int dram_size;
|
||||
unsigned int mbox_offset;
|
||||
unsigned int mbox_size;
|
||||
unsigned int acpi_lpe_res_index;
|
||||
unsigned int acpi_ddr_index;
|
||||
unsigned int acpi_ipc_irq_index;
|
||||
};
|
||||
|
||||
struct sst_ipc_info {
|
||||
int ipc_offset;
|
||||
unsigned int mbox_recv_off;
|
||||
};
|
||||
|
||||
struct sst_platform_info {
|
||||
const struct sst_info *probe_data;
|
||||
const struct sst_ipc_info *ipc_info;
|
||||
const struct sst_res_info *res_info;
|
||||
const struct sst_lib_dnld_info *lib_info;
|
||||
const char *platform;
|
||||
};
|
||||
int add_sst_platform_device(void);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ static struct snd_soc_dai_driver hdmi_codec_dai = {
|
||||
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.sig_bits = 24,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
@@ -75,6 +76,7 @@ static struct snd_soc_codec_driver hdmi_codec = {
|
||||
.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
|
||||
.dapm_routes = hdmi_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(hdmi_routes),
|
||||
.ignore_pmdown_time = true,
|
||||
};
|
||||
|
||||
static int hdmi_codec_probe(struct platform_device *pdev)
|
||||
|
||||
@@ -1395,15 +1395,7 @@ static struct snd_soc_dai_driver lm49453_dai[] = {
|
||||
},
|
||||
};
|
||||
|
||||
/* power down chip */
|
||||
static int lm49453_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
|
||||
.remove = lm49453_remove,
|
||||
.set_bias_level = lm49453_set_bias_level,
|
||||
.controls = lm49453_snd_controls,
|
||||
.num_controls = ARRAY_SIZE(lm49453_snd_controls),
|
||||
|
||||
+42
-2
@@ -3,6 +3,7 @@ config SND_MFLD_MACHINE
|
||||
depends on INTEL_SCU_IPC
|
||||
select SND_SOC_SN95031
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_IPC_PCI
|
||||
help
|
||||
This adds support for ASoC machine driver for Intel(R) MID Medfield platform
|
||||
used as alsa device in audio substem in Intel(R) MID devices
|
||||
@@ -12,10 +13,23 @@ config SND_MFLD_MACHINE
|
||||
config SND_SST_MFLD_PLATFORM
|
||||
tristate
|
||||
|
||||
config SND_SST_IPC
|
||||
tristate
|
||||
|
||||
config SND_SST_IPC_PCI
|
||||
tristate
|
||||
select SND_SST_IPC
|
||||
|
||||
config SND_SST_IPC_ACPI
|
||||
tristate
|
||||
select SND_SST_IPC
|
||||
depends on ACPI
|
||||
|
||||
config SND_SOC_INTEL_SST
|
||||
tristate "ASoC support for Intel(R) Smart Sound Technology"
|
||||
select SND_SOC_INTEL_SST_ACPI if ACPI
|
||||
depends on (X86 || COMPILE_TEST)
|
||||
depends on DW_DMAC_CORE
|
||||
help
|
||||
This adds support for Intel(R) Smart Sound Technology (SST).
|
||||
Say Y if you have such a device
|
||||
@@ -32,7 +46,8 @@ config SND_SOC_INTEL_BAYTRAIL
|
||||
|
||||
config SND_SOC_INTEL_HASWELL_MACH
|
||||
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
|
||||
depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C
|
||||
depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \\
|
||||
I2C_DESIGNWARE_PLATFORM
|
||||
select SND_SOC_INTEL_HASWELL
|
||||
select SND_SOC_RT5640
|
||||
help
|
||||
@@ -61,7 +76,8 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
|
||||
|
||||
config SND_SOC_INTEL_BROADWELL_MACH
|
||||
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
|
||||
depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC
|
||||
depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \\
|
||||
I2C_DESIGNWARE_PLATFORM
|
||||
select SND_SOC_INTEL_HASWELL
|
||||
select SND_COMPRESS_OFFLOAD
|
||||
select SND_SOC_RT286
|
||||
@@ -70,3 +86,27 @@ config SND_SOC_INTEL_BROADWELL_MACH
|
||||
Ultrabook platforms.
|
||||
Say Y if you have such a device
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_INTEL_BYTCR_RT5640_MACH
|
||||
tristate "ASoC Audio DSP Support for MID BYT Platform"
|
||||
depends on X86
|
||||
select SND_SOC_RT5640
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
help
|
||||
This adds support for ASoC machine driver for Intel(R) MID Baytrail platform
|
||||
used as alsa device in audio substem in Intel(R) MID devices
|
||||
Say Y if you have such a device
|
||||
If unsure select "N".
|
||||
|
||||
config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
|
||||
tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
|
||||
depends on X86_INTEL_LPSS
|
||||
select SND_SOC_RT5670
|
||||
select SND_SST_MFLD_PLATFORM
|
||||
select SND_SST_IPC_ACPI
|
||||
help
|
||||
This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
|
||||
platforms with RT5672 audio codec.
|
||||
Say Y if you have such a device
|
||||
If unsure select "N".
|
||||
|
||||
@@ -26,8 +26,15 @@ snd-soc-sst-haswell-objs := haswell.o
|
||||
snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
|
||||
snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
|
||||
snd-soc-sst-broadwell-objs := broadwell.o
|
||||
snd-soc-sst-bytcr-dpcm-rt5640-objs := bytcr_dpcm_rt5640.o
|
||||
snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-dpcm-rt5640.o
|
||||
obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
|
||||
|
||||
# DSP driver
|
||||
obj-$(CONFIG_SND_SST_IPC) += sst/
|
||||
|
||||
+48
-16
@@ -19,6 +19,7 @@
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "sst-dsp.h"
|
||||
@@ -26,8 +27,26 @@
|
||||
|
||||
#include "../codecs/rt286.h"
|
||||
|
||||
static struct snd_soc_jack broadwell_headset;
|
||||
/* Headset jack detection DAPM pins */
|
||||
static struct snd_soc_jack_pin broadwell_headset_pins[] = {
|
||||
{
|
||||
.pin = "Mic Jack",
|
||||
.mask = SND_JACK_MICROPHONE,
|
||||
},
|
||||
{
|
||||
.pin = "Headphone Jack",
|
||||
.mask = SND_JACK_HEADPHONE,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new broadwell_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Speaker"),
|
||||
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget broadwell_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphones", NULL),
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
SND_SOC_DAPM_MIC("Mic Jack", NULL),
|
||||
SND_SOC_DAPM_MIC("DMIC1", NULL),
|
||||
@@ -42,7 +61,7 @@ static const struct snd_soc_dapm_route broadwell_rt286_map[] = {
|
||||
{"Speaker", NULL, "SPOL"},
|
||||
|
||||
/* HP jack connectors - unknown if we have jack deteck */
|
||||
{"Headphones", NULL, "HPO Pin"},
|
||||
{"Headphone Jack", NULL, "HPO Pin"},
|
||||
|
||||
/* other jacks */
|
||||
{"MIC1", NULL, "Mic Jack"},
|
||||
@@ -57,6 +76,27 @@ static const struct snd_soc_dapm_route broadwell_rt286_map[] = {
|
||||
{"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
|
||||
};
|
||||
|
||||
static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
int ret = 0;
|
||||
ret = snd_soc_jack_new(codec, "Headset",
|
||||
SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_jack_add_pins(&broadwell_headset,
|
||||
ARRAY_SIZE(broadwell_headset_pins),
|
||||
broadwell_headset_pins);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rt286_mic_detect(codec, &broadwell_headset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
@@ -116,7 +156,7 @@ static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
|
||||
}
|
||||
|
||||
/* always connected - check HP for jack detect */
|
||||
snd_soc_dapm_enable_pin(dapm, "Headphones");
|
||||
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
|
||||
snd_soc_dapm_enable_pin(dapm, "Speaker");
|
||||
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
|
||||
snd_soc_dapm_enable_pin(dapm, "Line Jack");
|
||||
@@ -131,7 +171,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
|
||||
/* Front End DAI links */
|
||||
{
|
||||
.name = "System PCM",
|
||||
.stream_name = "System Playback",
|
||||
.stream_name = "System Playback/Capture",
|
||||
.cpu_dai_name = "System Pin",
|
||||
.platform_name = "haswell-pcm-audio",
|
||||
.dynamic = 1,
|
||||
@@ -140,6 +180,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
|
||||
.init = broadwell_rtd_init,
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
{
|
||||
.name = "Offload0",
|
||||
@@ -174,18 +215,6 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
{
|
||||
.name = "Capture PCM",
|
||||
.stream_name = "Capture",
|
||||
.cpu_dai_name = "Capture Pin",
|
||||
.platform_name = "haswell-pcm-audio",
|
||||
.dynamic = 1,
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
|
||||
/* Back End DAI links */
|
||||
{
|
||||
/* SSP0 - Codec */
|
||||
@@ -196,6 +225,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
|
||||
.no_pcm = 1,
|
||||
.codec_name = "i2c-INT343A:00",
|
||||
.codec_dai_name = "rt286-aif1",
|
||||
.init = broadwell_rt286_codec_init,
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS,
|
||||
.ignore_suspend = 1,
|
||||
@@ -213,6 +243,8 @@ static struct snd_soc_card broadwell_rt286 = {
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = broadwell_rt286_dais,
|
||||
.num_links = ARRAY_SIZE(broadwell_rt286_dais),
|
||||
.controls = broadwell_controls,
|
||||
.num_controls = ARRAY_SIZE(broadwell_controls),
|
||||
.dapm_widgets = broadwell_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(broadwell_widgets),
|
||||
.dapm_routes = broadwell_rt286_map,
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* byt_cr_dpcm_rt5640.c - ASoc Machine driver for Intel Byt CR platform
|
||||
*
|
||||
* Copyright (C) 2014 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.
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include "../codecs/rt5640.h"
|
||||
#include "sst-atom-controls.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget byt_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone", NULL),
|
||||
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
||||
SND_SOC_DAPM_MIC("Int Mic", NULL),
|
||||
SND_SOC_DAPM_SPK("Ext Spk", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route byt_audio_map[] = {
|
||||
{"IN2P", NULL, "Headset Mic"},
|
||||
{"IN2N", NULL, "Headset Mic"},
|
||||
{"Headset Mic", NULL, "MICBIAS1"},
|
||||
{"IN1P", NULL, "MICBIAS1"},
|
||||
{"LDO2", NULL, "Int Mic"},
|
||||
{"Headphone", NULL, "HPOL"},
|
||||
{"Headphone", NULL, "HPOR"},
|
||||
{"Ext Spk", NULL, "SPOLP"},
|
||||
{"Ext Spk", NULL, "SPOLN"},
|
||||
{"Ext Spk", NULL, "SPORP"},
|
||||
{"Ext Spk", NULL, "SPORN"},
|
||||
|
||||
{"AIF1 Playback", NULL, "ssp2 Tx"},
|
||||
{"ssp2 Tx", NULL, "codec_out0"},
|
||||
{"ssp2 Tx", NULL, "codec_out1"},
|
||||
{"codec_in0", NULL, "ssp2 Rx"},
|
||||
{"codec_in1", NULL, "ssp2 Rx"},
|
||||
{"ssp2 Rx", NULL, "AIF1 Capture"},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new byt_mc_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Headphone"),
|
||||
SOC_DAPM_PIN_SWITCH("Headset Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Int Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Ext Spk"),
|
||||
};
|
||||
|
||||
static int byt_aif1_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
|
||||
snd_soc_dai_set_bclk_ratio(codec_dai, 50);
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
|
||||
params_rate(params) * 512,
|
||||
SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set codec clock %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1,
|
||||
params_rate(params) * 50,
|
||||
params_rate(params) * 512);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_pcm_stream byt_dai_params = {
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_LE,
|
||||
.rate_min = 48000,
|
||||
.rate_max = 48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
};
|
||||
|
||||
static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_interval *rate = hw_param_interval(params,
|
||||
SNDRV_PCM_HW_PARAM_RATE);
|
||||
struct snd_interval *channels = hw_param_interval(params,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS);
|
||||
|
||||
/* The DSP will covert the FE rate to 48k, stereo, 24bits */
|
||||
rate->min = rate->max = 48000;
|
||||
channels->min = channels->max = 2;
|
||||
|
||||
/* set SSP2 to 24-bit */
|
||||
snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT -
|
||||
SNDRV_PCM_HW_PARAM_FIRST_MASK],
|
||||
SNDRV_PCM_FORMAT_S24_LE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int rates_48000[] = {
|
||||
48000,
|
||||
};
|
||||
|
||||
static struct snd_pcm_hw_constraint_list constraints_48000 = {
|
||||
.count = ARRAY_SIZE(rates_48000),
|
||||
.list = rates_48000,
|
||||
};
|
||||
|
||||
static int byt_aif1_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_48000);
|
||||
}
|
||||
|
||||
static struct snd_soc_ops byt_aif1_ops = {
|
||||
.startup = byt_aif1_startup,
|
||||
};
|
||||
|
||||
static struct snd_soc_ops byt_be_ssp2_ops = {
|
||||
.hw_params = byt_aif1_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link byt_dailink[] = {
|
||||
[MERR_DPCM_AUDIO] = {
|
||||
.name = "Baytrail Audio Port",
|
||||
.stream_name = "Baytrail Audio",
|
||||
.cpu_dai_name = "media-cpu-dai",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.ignore_suspend = 1,
|
||||
.dynamic = 1,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
.ops = &byt_aif1_ops,
|
||||
},
|
||||
[MERR_DPCM_COMPR] = {
|
||||
.name = "Baytrail Compressed Port",
|
||||
.stream_name = "Baytrail Compress",
|
||||
.cpu_dai_name = "compress-cpu-dai",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
},
|
||||
/* back ends */
|
||||
{
|
||||
.name = "SSP2-Codec",
|
||||
.be_id = 1,
|
||||
.cpu_dai_name = "ssp2-port",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.no_pcm = 1,
|
||||
.codec_dai_name = "rt5640-aif1",
|
||||
.codec_name = "i2c-10EC5640:00",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
|
||||
| SND_SOC_DAIFMT_CBS_CFS,
|
||||
.be_hw_params_fixup = byt_codec_fixup,
|
||||
.ignore_suspend = 1,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
.ops = &byt_be_ssp2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
/* SoC card */
|
||||
static struct snd_soc_card snd_soc_card_byt = {
|
||||
.name = "baytrailcraudio",
|
||||
.dai_link = byt_dailink,
|
||||
.num_links = ARRAY_SIZE(byt_dailink),
|
||||
.dapm_widgets = byt_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(byt_dapm_widgets),
|
||||
.dapm_routes = byt_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(byt_audio_map),
|
||||
.controls = byt_mc_controls,
|
||||
.num_controls = ARRAY_SIZE(byt_mc_controls),
|
||||
};
|
||||
|
||||
static int snd_byt_mc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret_val = 0;
|
||||
|
||||
/* register the soc card */
|
||||
snd_soc_card_byt.dev = &pdev->dev;
|
||||
|
||||
ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_byt);
|
||||
if (ret_val) {
|
||||
dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", ret_val);
|
||||
return ret_val;
|
||||
}
|
||||
platform_set_drvdata(pdev, &snd_soc_card_byt);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static struct platform_driver snd_byt_mc_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "bytt100_rt5640",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = snd_byt_mc_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(snd_byt_mc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
|
||||
MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:bytrt5640-audio");
|
||||
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms
|
||||
* Cherrytrail and Braswell, with RT5672 codec.
|
||||
*
|
||||
* Copyright (C) 2014 Intel Corp
|
||||
* Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
|
||||
* Mengdong Lin <mengdong.lin@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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include "../codecs/rt5670.h"
|
||||
#include "sst-atom-controls.h"
|
||||
|
||||
/* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */
|
||||
#define CHT_PLAT_CLK_3_HZ 19200000
|
||||
#define CHT_CODEC_DAI "rt5670-aif1"
|
||||
|
||||
static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < card->num_rtd; i++) {
|
||||
struct snd_soc_pcm_runtime *rtd;
|
||||
|
||||
rtd = card->rtd + i;
|
||||
if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
|
||||
strlen(CHT_CODEC_DAI)))
|
||||
return rtd->codec_dai;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int platform_clock_control(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *k, int event)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = w->dapm;
|
||||
struct snd_soc_card *card = dapm->card;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
|
||||
codec_dai = cht_get_codec_dai(card);
|
||||
if (!codec_dai) {
|
||||
dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!SND_SOC_DAPM_EVENT_OFF(event))
|
||||
return 0;
|
||||
|
||||
/* Set codec sysclk source to its internal clock because codec PLL will
|
||||
* be off when idle and MCLK will also be off by ACPI when codec is
|
||||
* runtime suspended. Codec needs clock for jack detection and button
|
||||
* press.
|
||||
*/
|
||||
snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK,
|
||||
0, SND_SOC_CLOCK_IN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone", NULL),
|
||||
SND_SOC_DAPM_MIC("Headset Mic", NULL),
|
||||
SND_SOC_DAPM_MIC("Int Mic", NULL),
|
||||
SND_SOC_DAPM_SPK("Ext Spk", NULL),
|
||||
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
|
||||
platform_clock_control, SND_SOC_DAPM_POST_PMD),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cht_audio_map[] = {
|
||||
{"IN1P", NULL, "Headset Mic"},
|
||||
{"IN1N", NULL, "Headset Mic"},
|
||||
{"DMIC L1", NULL, "Int Mic"},
|
||||
{"DMIC R1", NULL, "Int Mic"},
|
||||
{"Headphone", NULL, "HPOL"},
|
||||
{"Headphone", NULL, "HPOR"},
|
||||
{"Ext Spk", NULL, "SPOLP"},
|
||||
{"Ext Spk", NULL, "SPOLN"},
|
||||
{"Ext Spk", NULL, "SPORP"},
|
||||
{"Ext Spk", NULL, "SPORN"},
|
||||
{"AIF1 Playback", NULL, "ssp2 Tx"},
|
||||
{"ssp2 Tx", NULL, "codec_out0"},
|
||||
{"ssp2 Tx", NULL, "codec_out1"},
|
||||
{"codec_in0", NULL, "ssp2 Rx"},
|
||||
{"codec_in1", NULL, "ssp2 Rx"},
|
||||
{"ssp2 Rx", NULL, "AIF1 Capture"},
|
||||
{"Headphone", NULL, "Platform Clock"},
|
||||
{"Headset Mic", NULL, "Platform Clock"},
|
||||
{"Int Mic", NULL, "Platform Clock"},
|
||||
{"Ext Spk", NULL, "Platform Clock"},
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new cht_mc_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Headphone"),
|
||||
SOC_DAPM_PIN_SWITCH("Headset Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Int Mic"),
|
||||
SOC_DAPM_PIN_SWITCH("Ext Spk"),
|
||||
};
|
||||
|
||||
static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
|
||||
/* set codec PLL source to the 19.2MHz platform clock (MCLK) */
|
||||
ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK,
|
||||
CHT_PLAT_CLK_3_HZ, params_rate(params) * 512);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set codec sysclk source to PLL */
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1,
|
||||
params_rate(params) * 512,
|
||||
SND_SOC_CLOCK_IN);
|
||||
if (ret < 0) {
|
||||
dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_dai *codec_dai = runtime->codec_dai;
|
||||
|
||||
/* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
|
||||
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
|
||||
if (ret < 0) {
|
||||
dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_interval *rate = hw_param_interval(params,
|
||||
SNDRV_PCM_HW_PARAM_RATE);
|
||||
struct snd_interval *channels = hw_param_interval(params,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS);
|
||||
|
||||
/* The DSP will covert the FE rate to 48k, stereo, 24bits */
|
||||
rate->min = rate->max = 48000;
|
||||
channels->min = channels->max = 2;
|
||||
|
||||
/* set SSP2 to 24-bit */
|
||||
snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT -
|
||||
SNDRV_PCM_HW_PARAM_FIRST_MASK],
|
||||
SNDRV_PCM_FORMAT_S24_LE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int rates_48000[] = {
|
||||
48000,
|
||||
};
|
||||
|
||||
static struct snd_pcm_hw_constraint_list constraints_48000 = {
|
||||
.count = ARRAY_SIZE(rates_48000),
|
||||
.list = rates_48000,
|
||||
};
|
||||
|
||||
static int cht_aif1_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return snd_pcm_hw_constraint_list(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
&constraints_48000);
|
||||
}
|
||||
|
||||
static struct snd_soc_ops cht_aif1_ops = {
|
||||
.startup = cht_aif1_startup,
|
||||
};
|
||||
|
||||
static struct snd_soc_ops cht_be_ssp2_ops = {
|
||||
.hw_params = cht_aif1_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link cht_dailink[] = {
|
||||
/* Front End DAI links */
|
||||
[MERR_DPCM_AUDIO] = {
|
||||
.name = "Audio Port",
|
||||
.stream_name = "Audio",
|
||||
.cpu_dai_name = "media-cpu-dai",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.ignore_suspend = 1,
|
||||
.dynamic = 1,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
.ops = &cht_aif1_ops,
|
||||
},
|
||||
[MERR_DPCM_COMPR] = {
|
||||
.name = "Compressed Port",
|
||||
.stream_name = "Compress",
|
||||
.cpu_dai_name = "compress-cpu-dai",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
},
|
||||
|
||||
/* Back End DAI links */
|
||||
{
|
||||
/* SSP2 - Codec */
|
||||
.name = "SSP2-Codec",
|
||||
.be_id = 1,
|
||||
.cpu_dai_name = "ssp2-port",
|
||||
.platform_name = "sst-mfld-platform",
|
||||
.no_pcm = 1,
|
||||
.codec_dai_name = "rt5670-aif1",
|
||||
.codec_name = "i2c-10EC5670:00",
|
||||
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
|
||||
| SND_SOC_DAIFMT_CBS_CFS,
|
||||
.init = cht_codec_init,
|
||||
.be_hw_params_fixup = cht_codec_fixup,
|
||||
.ignore_suspend = 1,
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
.ops = &cht_be_ssp2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
/* SoC card */
|
||||
static struct snd_soc_card snd_soc_card_cht = {
|
||||
.name = "cherrytrailcraudio",
|
||||
.dai_link = cht_dailink,
|
||||
.num_links = ARRAY_SIZE(cht_dailink),
|
||||
.dapm_widgets = cht_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
|
||||
.dapm_routes = cht_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(cht_audio_map),
|
||||
.controls = cht_mc_controls,
|
||||
.num_controls = ARRAY_SIZE(cht_mc_controls),
|
||||
};
|
||||
|
||||
static int snd_cht_mc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret_val = 0;
|
||||
|
||||
/* register the soc card */
|
||||
snd_soc_card_cht.dev = &pdev->dev;
|
||||
ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
|
||||
if (ret_val) {
|
||||
dev_err(&pdev->dev,
|
||||
"snd_soc_register_card failed %d\n", ret_val);
|
||||
return ret_val;
|
||||
}
|
||||
platform_set_drvdata(pdev, &snd_soc_card_cht);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static struct platform_driver snd_cht_mc_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "cht-bsw-rt5672",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = snd_cht_mc_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(snd_cht_mc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
|
||||
MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:cht-bsw-rt5672");
|
||||
@@ -109,7 +109,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = {
|
||||
/* Front End DAI links */
|
||||
{
|
||||
.name = "System",
|
||||
.stream_name = "System Playback",
|
||||
.stream_name = "System Playback/Capture",
|
||||
.cpu_dai_name = "System Pin",
|
||||
.platform_name = "haswell-pcm-audio",
|
||||
.dynamic = 1,
|
||||
@@ -118,6 +118,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = {
|
||||
.init = haswell_rtd_init,
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
|
||||
.dpcm_playback = 1,
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
{
|
||||
.name = "Offload0",
|
||||
@@ -152,17 +153,6 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = {
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
{
|
||||
.name = "Capture",
|
||||
.stream_name = "Capture",
|
||||
.cpu_dai_name = "Capture Pin",
|
||||
.platform_name = "haswell-pcm-audio",
|
||||
.dynamic = 1,
|
||||
.codec_name = "snd-soc-dummy",
|
||||
.codec_dai_name = "snd-soc-dummy-dai",
|
||||
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
|
||||
.dpcm_capture = 1,
|
||||
},
|
||||
|
||||
/* Back End DAI links */
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,9 @@
|
||||
#ifndef __SST_ATOM_CONTROLS_H__
|
||||
#define __SST_ATOM_CONTROLS_H__
|
||||
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
enum {
|
||||
MERR_DPCM_AUDIO = 0,
|
||||
MERR_DPCM_COMPR,
|
||||
@@ -360,16 +363,416 @@ struct sst_dsp_header {
|
||||
struct sst_cmd_generic {
|
||||
struct sst_dsp_header header;
|
||||
} __packed;
|
||||
|
||||
struct swm_input_ids {
|
||||
struct sst_destination_id input_id;
|
||||
} __packed;
|
||||
|
||||
struct sst_cmd_set_swm {
|
||||
struct sst_dsp_header header;
|
||||
struct sst_destination_id output_id;
|
||||
u16 switch_state;
|
||||
u16 nb_inputs;
|
||||
struct swm_input_ids input[SST_CMD_SWM_MAX_INPUTS];
|
||||
} __packed;
|
||||
|
||||
struct sst_cmd_set_media_path {
|
||||
struct sst_dsp_header header;
|
||||
u16 switch_state;
|
||||
} __packed;
|
||||
|
||||
struct pcm_cfg {
|
||||
u8 s_length:2;
|
||||
u8 rate:3;
|
||||
u8 format:3;
|
||||
} __packed;
|
||||
|
||||
struct sst_cmd_set_speech_path {
|
||||
struct sst_dsp_header header;
|
||||
u16 switch_state;
|
||||
struct {
|
||||
u16 rsvd:8;
|
||||
struct pcm_cfg cfg;
|
||||
} config;
|
||||
} __packed;
|
||||
|
||||
struct gain_cell {
|
||||
struct sst_destination_id dest;
|
||||
s16 cell_gain_left;
|
||||
s16 cell_gain_right;
|
||||
u16 gain_time_constant;
|
||||
} __packed;
|
||||
|
||||
#define NUM_GAIN_CELLS 1
|
||||
struct sst_cmd_set_gain_dual {
|
||||
struct sst_dsp_header header;
|
||||
u16 gain_cell_num;
|
||||
struct gain_cell cell_gains[NUM_GAIN_CELLS];
|
||||
} __packed;
|
||||
struct sst_cmd_set_params {
|
||||
struct sst_destination_id dst;
|
||||
u16 command_id;
|
||||
char params[0];
|
||||
} __packed;
|
||||
|
||||
|
||||
struct sst_cmd_sba_vb_start {
|
||||
struct sst_dsp_header header;
|
||||
} __packed;
|
||||
|
||||
union sba_media_loop_params {
|
||||
struct {
|
||||
u16 rsvd:8;
|
||||
struct pcm_cfg cfg;
|
||||
} part;
|
||||
u16 full;
|
||||
} __packed;
|
||||
|
||||
struct sst_cmd_sba_set_media_loop_map {
|
||||
struct sst_dsp_header header;
|
||||
u16 switch_state;
|
||||
union sba_media_loop_params param;
|
||||
u16 map;
|
||||
} __packed;
|
||||
|
||||
struct sst_cmd_tone_stop {
|
||||
struct sst_dsp_header header;
|
||||
u16 switch_state;
|
||||
} __packed;
|
||||
|
||||
enum sst_ssp_mode {
|
||||
SSP_MODE_MASTER = 0,
|
||||
SSP_MODE_SLAVE = 1,
|
||||
};
|
||||
|
||||
enum sst_ssp_pcm_mode {
|
||||
SSP_PCM_MODE_NORMAL = 0,
|
||||
SSP_PCM_MODE_NETWORK = 1,
|
||||
};
|
||||
|
||||
enum sst_ssp_duplex {
|
||||
SSP_DUPLEX = 0,
|
||||
SSP_RX = 1,
|
||||
SSP_TX = 2,
|
||||
};
|
||||
|
||||
enum sst_ssp_fs_frequency {
|
||||
SSP_FS_8_KHZ = 0,
|
||||
SSP_FS_16_KHZ = 1,
|
||||
SSP_FS_44_1_KHZ = 2,
|
||||
SSP_FS_48_KHZ = 3,
|
||||
};
|
||||
|
||||
enum sst_ssp_fs_polarity {
|
||||
SSP_FS_ACTIVE_LOW = 0,
|
||||
SSP_FS_ACTIVE_HIGH = 1,
|
||||
};
|
||||
|
||||
enum sst_ssp_protocol {
|
||||
SSP_MODE_PCM = 0,
|
||||
SSP_MODE_I2S = 1,
|
||||
};
|
||||
|
||||
enum sst_ssp_port_id {
|
||||
SSP_MODEM = 0,
|
||||
SSP_BT = 1,
|
||||
SSP_FM = 2,
|
||||
SSP_CODEC = 3,
|
||||
};
|
||||
|
||||
struct sst_cmd_sba_hw_set_ssp {
|
||||
struct sst_dsp_header header;
|
||||
u16 selection; /* 0:SSP0(def), 1:SSP1, 2:SSP2 */
|
||||
|
||||
u16 switch_state;
|
||||
|
||||
u16 nb_bits_per_slots:6; /* 0-32 bits, 24 (def) */
|
||||
u16 nb_slots:4; /* 0-8: slots per frame */
|
||||
u16 mode:3; /* 0:Master, 1: Slave */
|
||||
u16 duplex:3;
|
||||
|
||||
u16 active_tx_slot_map:8; /* Bit map, 0:off, 1:on */
|
||||
u16 reserved1:8;
|
||||
|
||||
u16 active_rx_slot_map:8; /* Bit map 0: Off, 1:On */
|
||||
u16 reserved2:8;
|
||||
|
||||
u16 frame_sync_frequency;
|
||||
|
||||
u16 frame_sync_polarity:8;
|
||||
u16 data_polarity:8;
|
||||
|
||||
u16 frame_sync_width; /* 1 to N clocks */
|
||||
u16 ssp_protocol:8;
|
||||
u16 start_delay:8; /* Start delay in terms of clock ticks */
|
||||
} __packed;
|
||||
|
||||
#define SST_MAX_TDM_SLOTS 8
|
||||
|
||||
struct sst_param_sba_ssp_slot_map {
|
||||
struct sst_dsp_header header;
|
||||
|
||||
u16 param_id;
|
||||
u16 param_len;
|
||||
u16 ssp_index;
|
||||
|
||||
u8 rx_slot_map[SST_MAX_TDM_SLOTS];
|
||||
u8 tx_slot_map[SST_MAX_TDM_SLOTS];
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
SST_PROBE_EXTRACTOR = 0,
|
||||
SST_PROBE_INJECTOR = 1,
|
||||
};
|
||||
|
||||
/**** widget defines *****/
|
||||
|
||||
#define SST_MODULE_GAIN 1
|
||||
#define SST_MODULE_ALGO 2
|
||||
|
||||
#define SST_FMT_MONO 0
|
||||
#define SST_FMT_STEREO 3
|
||||
|
||||
/* physical SSP numbers */
|
||||
enum {
|
||||
SST_SSP0 = 0,
|
||||
SST_SSP1,
|
||||
SST_SSP2,
|
||||
SST_SSP_LAST = SST_SSP2,
|
||||
};
|
||||
|
||||
#define SST_NUM_SSPS (SST_SSP_LAST + 1) /* physical SSPs */
|
||||
#define SST_MAX_SSP_MUX 2 /* single SSP muxed between pipes */
|
||||
#define SST_MAX_SSP_DOMAINS 2 /* domains present in each pipe */
|
||||
|
||||
struct sst_module {
|
||||
struct snd_kcontrol *kctl;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
struct sst_ssp_config {
|
||||
u8 ssp_id;
|
||||
u8 bits_per_slot;
|
||||
u8 slots;
|
||||
u8 ssp_mode;
|
||||
u8 pcm_mode;
|
||||
u8 duplex;
|
||||
u8 ssp_protocol;
|
||||
u8 fs_frequency;
|
||||
u8 active_slot_map;
|
||||
u8 start_delay;
|
||||
u16 fs_width;
|
||||
};
|
||||
|
||||
struct sst_ssp_cfg {
|
||||
const u8 ssp_number;
|
||||
const int *mux_shift;
|
||||
const int (*domain_shift)[SST_MAX_SSP_MUX];
|
||||
const struct sst_ssp_config (*ssp_config)[SST_MAX_SSP_MUX][SST_MAX_SSP_DOMAINS];
|
||||
};
|
||||
|
||||
struct sst_ids {
|
||||
u16 location_id;
|
||||
u16 module_id;
|
||||
u8 task_id;
|
||||
u8 format;
|
||||
u8 reg;
|
||||
const char *parent_wname;
|
||||
struct snd_soc_dapm_widget *parent_w;
|
||||
struct list_head algo_list;
|
||||
struct list_head gain_list;
|
||||
const struct sst_pcm_format *pcm_fmt;
|
||||
};
|
||||
|
||||
|
||||
#define SST_AIF_IN(wname, wevent) \
|
||||
{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = NULL, \
|
||||
.reg = SND_SOC_NOPM, .shift = 0, \
|
||||
.on_val = 1, .off_val = 0, \
|
||||
.event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
|
||||
.priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \
|
||||
}
|
||||
|
||||
#define SST_AIF_OUT(wname, wevent) \
|
||||
{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = NULL, \
|
||||
.reg = SND_SOC_NOPM, .shift = 0, \
|
||||
.on_val = 1, .off_val = 0, \
|
||||
.event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
|
||||
.priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \
|
||||
}
|
||||
|
||||
#define SST_INPUT(wname, wevent) \
|
||||
{ .id = snd_soc_dapm_input, .name = wname, .sname = NULL, \
|
||||
.reg = SND_SOC_NOPM, .shift = 0, \
|
||||
.on_val = 1, .off_val = 0, \
|
||||
.event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
|
||||
.priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \
|
||||
}
|
||||
|
||||
#define SST_OUTPUT(wname, wevent) \
|
||||
{ .id = snd_soc_dapm_output, .name = wname, .sname = NULL, \
|
||||
.reg = SND_SOC_NOPM, .shift = 0, \
|
||||
.on_val = 1, .off_val = 0, \
|
||||
.event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
|
||||
.priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \
|
||||
}
|
||||
|
||||
#define SST_DAPM_OUTPUT(wname, wloc_id, wtask_id, wformat, wevent) \
|
||||
{ .id = snd_soc_dapm_output, .name = wname, .sname = NULL, \
|
||||
.reg = SND_SOC_NOPM, .shift = 0, \
|
||||
.on_val = 1, .off_val = 0, \
|
||||
.event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
|
||||
.priv = (void *)&(struct sst_ids) { .location_id = wloc_id, .task_id = wtask_id,\
|
||||
.pcm_fmt = wformat, } \
|
||||
}
|
||||
|
||||
#define SST_PATH(wname, wtask, wloc_id, wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \
|
||||
.kcontrol_news = NULL, .num_kcontrols = 0, \
|
||||
.on_val = 1, .off_val = 0, \
|
||||
.event = wevent, .event_flags = wflags, \
|
||||
.priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, } \
|
||||
}
|
||||
|
||||
#define SST_LINKED_PATH(wname, wtask, wloc_id, linked_wname, wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \
|
||||
.kcontrol_news = NULL, .num_kcontrols = 0, \
|
||||
.on_val = 1, .off_val = 0, \
|
||||
.event = wevent, .event_flags = wflags, \
|
||||
.priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, \
|
||||
.parent_wname = linked_wname} \
|
||||
}
|
||||
|
||||
#define SST_PATH_MEDIA_LOOP(wname, wtask, wloc_id, wformat, wevent, wflags) \
|
||||
{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \
|
||||
.kcontrol_news = NULL, .num_kcontrols = 0, \
|
||||
.event = wevent, .event_flags = wflags, \
|
||||
.priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, \
|
||||
.format = wformat,} \
|
||||
}
|
||||
|
||||
/* output is triggered before input */
|
||||
#define SST_PATH_INPUT(name, task_id, loc_id, event) \
|
||||
SST_PATH(name, task_id, loc_id, event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
|
||||
|
||||
#define SST_PATH_LINKED_INPUT(name, task_id, loc_id, linked_wname, event) \
|
||||
SST_LINKED_PATH(name, task_id, loc_id, linked_wname, event, \
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
|
||||
|
||||
#define SST_PATH_OUTPUT(name, task_id, loc_id, event) \
|
||||
SST_PATH(name, task_id, loc_id, event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)
|
||||
|
||||
#define SST_PATH_LINKED_OUTPUT(name, task_id, loc_id, linked_wname, event) \
|
||||
SST_LINKED_PATH(name, task_id, loc_id, linked_wname, event, \
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)
|
||||
|
||||
#define SST_PATH_MEDIA_LOOP_OUTPUT(name, task_id, loc_id, format, event) \
|
||||
SST_PATH_MEDIA_LOOP(name, task_id, loc_id, format, event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)
|
||||
|
||||
|
||||
#define SST_SWM_MIXER(wname, wreg, wtask, wloc_id, wcontrols, wevent) \
|
||||
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols),\
|
||||
.event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD | \
|
||||
SND_SOC_DAPM_POST_REG, \
|
||||
.priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, \
|
||||
.reg = wreg } \
|
||||
}
|
||||
|
||||
enum sst_gain_kcontrol_type {
|
||||
SST_GAIN_TLV,
|
||||
SST_GAIN_MUTE,
|
||||
SST_GAIN_RAMP_DURATION,
|
||||
};
|
||||
|
||||
struct sst_gain_mixer_control {
|
||||
bool stereo;
|
||||
enum sst_gain_kcontrol_type type;
|
||||
struct sst_gain_value *gain_val;
|
||||
int max;
|
||||
int min;
|
||||
u16 instance_id;
|
||||
u16 module_id;
|
||||
u16 pipe_id;
|
||||
u16 task_id;
|
||||
char pname[44];
|
||||
struct snd_soc_dapm_widget *w;
|
||||
};
|
||||
|
||||
struct sst_gain_value {
|
||||
u16 ramp_duration;
|
||||
s16 l_gain;
|
||||
s16 r_gain;
|
||||
bool mute;
|
||||
};
|
||||
#define SST_GAIN_VOLUME_DEFAULT (-1440)
|
||||
#define SST_GAIN_RAMP_DURATION_DEFAULT 5 /* timeconstant */
|
||||
#define SST_GAIN_MUTE_DEFAULT true
|
||||
|
||||
#define SST_GAIN_KCONTROL_TLV(xname, xhandler_get, xhandler_put, \
|
||||
xmod, xpipe, xinstance, xtask, tlv_array, xgain_val, \
|
||||
xmin, xmax, xpname) \
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
|
||||
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
|
||||
.tlv.p = (tlv_array), \
|
||||
.info = sst_gain_ctl_info,\
|
||||
.get = xhandler_get, .put = xhandler_put, \
|
||||
.private_value = (unsigned long)&(struct sst_gain_mixer_control) \
|
||||
{ .stereo = true, .max = xmax, .min = xmin, .type = SST_GAIN_TLV, \
|
||||
.module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\
|
||||
.instance_id = xinstance, .gain_val = xgain_val, .pname = xpname}
|
||||
|
||||
#define SST_GAIN_KCONTROL_INT(xname, xhandler_get, xhandler_put, \
|
||||
xmod, xpipe, xinstance, xtask, xtype, xgain_val, \
|
||||
xmin, xmax, xpname) \
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = sst_gain_ctl_info, \
|
||||
.get = xhandler_get, .put = xhandler_put, \
|
||||
.private_value = (unsigned long)&(struct sst_gain_mixer_control) \
|
||||
{ .stereo = false, .max = xmax, .min = xmin, .type = xtype, \
|
||||
.module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\
|
||||
.instance_id = xinstance, .gain_val = xgain_val, .pname = xpname}
|
||||
|
||||
#define SST_GAIN_KCONTROL_BOOL(xname, xhandler_get, xhandler_put,\
|
||||
xmod, xpipe, xinstance, xtask, xgain_val, xpname) \
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_bool_ext, \
|
||||
.get = xhandler_get, .put = xhandler_put, \
|
||||
.private_value = (unsigned long)&(struct sst_gain_mixer_control) \
|
||||
{ .stereo = false, .type = SST_GAIN_MUTE, \
|
||||
.module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\
|
||||
.instance_id = xinstance, .gain_val = xgain_val, .pname = xpname}
|
||||
#define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \
|
||||
xpname " " xmname " " #xinstance " " xtype
|
||||
|
||||
#define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \
|
||||
xpname " " xmname " " #xinstance " " xtype " " xsubmodule
|
||||
|
||||
/*
|
||||
* 3 Controls for each Gain module
|
||||
* e.g. - pcm0_in Gain 0 Volume
|
||||
* - pcm0_in Gain 0 Ramp Delay
|
||||
* - pcm0_in Gain 0 Switch
|
||||
*/
|
||||
#define SST_GAIN_KCONTROLS(xpname, xmname, xmin_gain, xmax_gain, xmin_tc, xmax_tc, \
|
||||
xhandler_get, xhandler_put, \
|
||||
xmod, xpipe, xinstance, xtask, tlv_array, xgain_val) \
|
||||
{ SST_GAIN_KCONTROL_INT(SST_CONTROL_NAME(xpname, xmname, xinstance, "Ramp Delay"), \
|
||||
xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, SST_GAIN_RAMP_DURATION, \
|
||||
xgain_val, xmin_tc, xmax_tc, xpname) }, \
|
||||
{ SST_GAIN_KCONTROL_BOOL(SST_CONTROL_NAME(xpname, xmname, xinstance, "Switch"), \
|
||||
xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, \
|
||||
xgain_val, xpname) } ,\
|
||||
{ SST_GAIN_KCONTROL_TLV(SST_CONTROL_NAME(xpname, xmname, xinstance, "Volume"), \
|
||||
xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, tlv_array, \
|
||||
xgain_val, xmin_gain, xmax_gain, xpname) }
|
||||
|
||||
#define SST_GAIN_TC_MIN 5
|
||||
#define SST_GAIN_TC_MAX 5000
|
||||
#define SST_GAIN_MIN_VALUE -1440 /* in 0.1 DB units */
|
||||
#define SST_GAIN_MAX_VALUE 360
|
||||
|
||||
enum sst_algo_kcontrol_type {
|
||||
SST_ALGO_PARAMS,
|
||||
SST_ALGO_BYPASS,
|
||||
@@ -439,4 +842,29 @@ struct sst_enum {
|
||||
struct snd_soc_dapm_widget *w;
|
||||
};
|
||||
|
||||
/* only 4 slots/channels supported atm */
|
||||
#define SST_SSP_SLOT_ENUM(s_ch_no, is_tx, xtexts) \
|
||||
(struct sst_enum){ .reg = s_ch_no, .tx = is_tx, .max = 4+1, .texts = xtexts, }
|
||||
|
||||
#define SST_SLOT_CTL_NAME(xpname, xmname, s_ch_name) \
|
||||
xpname " " xmname " " s_ch_name
|
||||
|
||||
#define SST_SSP_SLOT_CTL(xpname, xmname, s_ch_name, s_ch_no, is_tx, xtexts, xget, xput) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
|
||||
.name = SST_SLOT_CTL_NAME(xpname, xmname, s_ch_name), \
|
||||
.info = sst_slot_enum_info, \
|
||||
.get = xget, .put = xput, \
|
||||
.private_value = (unsigned long)&SST_SSP_SLOT_ENUM(s_ch_no, is_tx, xtexts), \
|
||||
}
|
||||
|
||||
#define SST_MUX_CTL_NAME(xpname, xinstance) \
|
||||
xpname " " #xinstance
|
||||
|
||||
#define SST_SSP_MUX_ENUM(xreg, xshift, xtexts) \
|
||||
(struct soc_enum) SOC_ENUM_DOUBLE(xreg, xshift, xshift, ARRAY_SIZE(xtexts), xtexts)
|
||||
|
||||
#define SST_SSP_MUX_CTL(xpname, xinstance, xreg, xshift, xtexts) \
|
||||
SOC_DAPM_ENUM(SST_MUX_CTL_NAME(xpname, xinstance), \
|
||||
SST_SSP_MUX_ENUM(xreg, xshift, xtexts))
|
||||
|
||||
#endif
|
||||
|
||||
@@ -67,17 +67,12 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
|
||||
{
|
||||
struct dma_block_info *block;
|
||||
struct sst_module *mod;
|
||||
struct sst_module_data block_data;
|
||||
struct sst_module_template template;
|
||||
int count;
|
||||
|
||||
memset(&template, 0, sizeof(template));
|
||||
template.id = module->type;
|
||||
template.entry = module->entry_point;
|
||||
template.p.type = SST_MEM_DRAM;
|
||||
template.p.data_type = SST_DATA_P;
|
||||
template.s.type = SST_MEM_DRAM;
|
||||
template.s.data_type = SST_DATA_S;
|
||||
|
||||
mod = sst_module_new(fw, &template, NULL);
|
||||
if (mod == NULL)
|
||||
@@ -94,19 +89,19 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
|
||||
|
||||
switch (block->type) {
|
||||
case SST_BYT_IRAM:
|
||||
block_data.offset = block->ram_offset +
|
||||
mod->offset = block->ram_offset +
|
||||
dsp->addr.iram_offset;
|
||||
block_data.type = SST_MEM_IRAM;
|
||||
mod->type = SST_MEM_IRAM;
|
||||
break;
|
||||
case SST_BYT_DRAM:
|
||||
block_data.offset = block->ram_offset +
|
||||
mod->offset = block->ram_offset +
|
||||
dsp->addr.dram_offset;
|
||||
block_data.type = SST_MEM_DRAM;
|
||||
mod->type = SST_MEM_DRAM;
|
||||
break;
|
||||
case SST_BYT_CACHE:
|
||||
block_data.offset = block->ram_offset +
|
||||
mod->offset = block->ram_offset +
|
||||
(dsp->addr.fw_ext - dsp->addr.lpe);
|
||||
block_data.type = SST_MEM_CACHE;
|
||||
mod->type = SST_MEM_CACHE;
|
||||
break;
|
||||
default:
|
||||
dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n",
|
||||
@@ -114,11 +109,10 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
block_data.size = block->size;
|
||||
block_data.data_type = SST_DATA_M;
|
||||
block_data.data = (void *)block + sizeof(*block);
|
||||
mod->size = block->size;
|
||||
mod->data = (void *)block + sizeof(*block);
|
||||
|
||||
sst_module_insert_fixed_block(mod, &block_data);
|
||||
sst_module_alloc_blocks(mod);
|
||||
|
||||
block = (void *)block + sizeof(*block) + block->size;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,9 @@ struct sst_mem_block;
|
||||
struct sst_module;
|
||||
struct sst_fw;
|
||||
|
||||
/* do we need to remove or keep */
|
||||
#define DSP_DRAM_ADDR_OFFSET 0x400000
|
||||
|
||||
/*
|
||||
* DSP Operations exported by platform Audio DSP driver.
|
||||
*/
|
||||
@@ -33,6 +36,9 @@ struct sst_ops {
|
||||
/* DSP core boot / reset */
|
||||
void (*boot)(struct sst_dsp *);
|
||||
void (*reset)(struct sst_dsp *);
|
||||
int (*wake)(struct sst_dsp *);
|
||||
void (*sleep)(struct sst_dsp *);
|
||||
void (*stall)(struct sst_dsp *);
|
||||
|
||||
/* Shim IO */
|
||||
void (*write)(void __iomem *addr, u32 offset, u32 value);
|
||||
@@ -67,6 +73,8 @@ struct sst_addr {
|
||||
u32 shim_offset;
|
||||
u32 iram_offset;
|
||||
u32 dram_offset;
|
||||
u32 dsp_iram_offset;
|
||||
u32 dsp_dram_offset;
|
||||
void __iomem *lpe;
|
||||
void __iomem *shim;
|
||||
void __iomem *pci_cfg;
|
||||
@@ -83,15 +91,6 @@ struct sst_mailbox {
|
||||
size_t out_size;
|
||||
};
|
||||
|
||||
/*
|
||||
* Audio DSP Firmware data types.
|
||||
*/
|
||||
enum sst_data_type {
|
||||
SST_DATA_M = 0, /* module block data */
|
||||
SST_DATA_P = 1, /* peristant data (text, data) */
|
||||
SST_DATA_S = 2, /* scratch data (usually buffers) */
|
||||
};
|
||||
|
||||
/*
|
||||
* Audio DSP memory block types.
|
||||
*/
|
||||
@@ -124,23 +123,6 @@ struct sst_fw {
|
||||
void *private; /* core doesn't touch this */
|
||||
};
|
||||
|
||||
/*
|
||||
* Audio DSP Generic Module data.
|
||||
*
|
||||
* This is used to dsecribe any sections of persistent (text and data) and
|
||||
* scratch (buffers) of module data in ADSP memory space.
|
||||
*/
|
||||
struct sst_module_data {
|
||||
|
||||
enum sst_mem_type type; /* destination memory type */
|
||||
enum sst_data_type data_type; /* type of module data */
|
||||
|
||||
u32 size; /* size in bytes */
|
||||
int32_t offset; /* offset in FW file */
|
||||
u32 data_offset; /* offset in ADSP memory space */
|
||||
void *data; /* module data */
|
||||
};
|
||||
|
||||
/*
|
||||
* Audio DSP Generic Module Template.
|
||||
*
|
||||
@@ -150,15 +132,52 @@ struct sst_module_data {
|
||||
struct sst_module_template {
|
||||
u32 id;
|
||||
u32 entry; /* entry point */
|
||||
struct sst_module_data s; /* scratch data */
|
||||
struct sst_module_data p; /* peristant data */
|
||||
u32 scratch_size;
|
||||
u32 persistent_size;
|
||||
};
|
||||
|
||||
/*
|
||||
* Block Allocator - Used to allocate blocks of DSP memory.
|
||||
*/
|
||||
struct sst_block_allocator {
|
||||
u32 id;
|
||||
u32 offset;
|
||||
int size;
|
||||
enum sst_mem_type type;
|
||||
};
|
||||
|
||||
/*
|
||||
* Runtime Module Instance - A module object can be instanciated multiple
|
||||
* times within the DSP FW.
|
||||
*/
|
||||
struct sst_module_runtime {
|
||||
struct sst_dsp *dsp;
|
||||
int id;
|
||||
struct sst_module *module; /* parent module we belong too */
|
||||
|
||||
u32 persistent_offset; /* private memory offset */
|
||||
void *private;
|
||||
|
||||
struct list_head list;
|
||||
struct list_head block_list; /* list of blocks used */
|
||||
};
|
||||
|
||||
/*
|
||||
* Runtime Module Context - The runtime context must be manually stored by the
|
||||
* driver prior to enter S3 and restored after leaving S3. This should really be
|
||||
* part of the memory context saved by the enter D3 message IPC ???
|
||||
*/
|
||||
struct sst_module_runtime_context {
|
||||
dma_addr_t dma_buffer;
|
||||
u32 *buffer;
|
||||
};
|
||||
|
||||
/*
|
||||
* Audio DSP Generic Module.
|
||||
*
|
||||
* Each Firmware file can consist of 1..N modules. A module can span multiple
|
||||
* ADSP memory blocks. The simplest FW will be a file with 1 module.
|
||||
* ADSP memory blocks. The simplest FW will be a file with 1 module. A module
|
||||
* can be instanciated multiple times in the DSP.
|
||||
*/
|
||||
struct sst_module {
|
||||
struct sst_dsp *dsp;
|
||||
@@ -167,10 +186,13 @@ struct sst_module {
|
||||
/* module configuration */
|
||||
u32 id;
|
||||
u32 entry; /* module entry point */
|
||||
u32 offset; /* module offset in firmware file */
|
||||
s32 offset; /* module offset in firmware file */
|
||||
u32 size; /* module size */
|
||||
struct sst_module_data s; /* scratch data */
|
||||
struct sst_module_data p; /* peristant data */
|
||||
u32 scratch_size; /* global scratch memory required */
|
||||
u32 persistent_size; /* private memory required */
|
||||
enum sst_mem_type type; /* destination memory type */
|
||||
u32 data_offset; /* offset in ADSP memory space */
|
||||
void *data; /* module data */
|
||||
|
||||
/* runtime */
|
||||
u32 usage_count; /* can be unloaded if count == 0 */
|
||||
@@ -180,6 +202,7 @@ struct sst_module {
|
||||
struct list_head block_list; /* Module list of blocks in use */
|
||||
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*/
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -208,7 +231,6 @@ struct sst_mem_block {
|
||||
struct sst_block_ops *ops; /* block operations, if any */
|
||||
|
||||
/* block status */
|
||||
enum sst_data_type data_type; /* data type held in this block */
|
||||
u32 bytes_used; /* bytes in use by modules */
|
||||
void *private; /* generic core does not touch this */
|
||||
int users; /* number of modules using this block */
|
||||
@@ -253,6 +275,11 @@ struct sst_dsp {
|
||||
struct list_head module_list;
|
||||
struct list_head fw_list;
|
||||
|
||||
/* scratch buffer */
|
||||
struct list_head scratch_block_list;
|
||||
u32 scratch_offset;
|
||||
u32 scratch_size;
|
||||
|
||||
/* platform data */
|
||||
struct sst_pdata *pdata;
|
||||
|
||||
@@ -290,18 +317,33 @@ void sst_fw_unload(struct sst_fw *sst_fw);
|
||||
/* Create/Free firmware modules */
|
||||
struct sst_module *sst_module_new(struct sst_fw *sst_fw,
|
||||
struct sst_module_template *template, void *private);
|
||||
void sst_module_free(struct sst_module *sst_module);
|
||||
int sst_module_insert(struct sst_module *sst_module);
|
||||
int sst_module_remove(struct sst_module *sst_module);
|
||||
int sst_module_insert_fixed_block(struct sst_module *module,
|
||||
struct sst_module_data *data);
|
||||
void sst_module_free(struct sst_module *module);
|
||||
struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id);
|
||||
int sst_module_alloc_blocks(struct sst_module *module);
|
||||
int sst_module_free_blocks(struct sst_module *module);
|
||||
|
||||
/* allocate/free pesistent/scratch memory regions managed by drv */
|
||||
struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp);
|
||||
void sst_mem_block_free_scratch(struct sst_dsp *dsp,
|
||||
struct sst_module *scratch);
|
||||
int sst_block_module_remove(struct sst_module *module);
|
||||
/* Create/Free firmware module runtime instances */
|
||||
struct sst_module_runtime *sst_module_runtime_new(struct sst_module *module,
|
||||
int id, void *private);
|
||||
void sst_module_runtime_free(struct sst_module_runtime *runtime);
|
||||
struct sst_module_runtime *sst_module_runtime_get_from_id(
|
||||
struct sst_module *module, u32 id);
|
||||
int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime,
|
||||
int offset);
|
||||
int sst_module_runtime_free_blocks(struct sst_module_runtime *runtime);
|
||||
int sst_module_runtime_save(struct sst_module_runtime *runtime,
|
||||
struct sst_module_runtime_context *context);
|
||||
int sst_module_runtime_restore(struct sst_module_runtime *runtime,
|
||||
struct sst_module_runtime_context *context);
|
||||
|
||||
/* generic block allocation */
|
||||
int sst_alloc_blocks(struct sst_dsp *dsp, struct sst_block_allocator *ba,
|
||||
struct list_head *block_list);
|
||||
int sst_free_blocks(struct sst_dsp *dsp, struct list_head *block_list);
|
||||
|
||||
/* scratch allocation */
|
||||
int sst_block_alloc_scratch(struct sst_dsp *dsp);
|
||||
void sst_block_free_scratch(struct sst_dsp *dsp);
|
||||
|
||||
/* Register the DSPs memory blocks - would be nice to read from ACPI */
|
||||
struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
|
||||
@@ -309,4 +351,10 @@ struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
|
||||
void *private);
|
||||
void sst_mem_block_unregister_all(struct sst_dsp *dsp);
|
||||
|
||||
/* Create/Free DMA resources */
|
||||
int sst_dma_new(struct sst_dsp *sst);
|
||||
void sst_dma_free(struct sst_dma *dma);
|
||||
|
||||
u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset,
|
||||
enum sst_mem_type type);
|
||||
#endif
|
||||
|
||||
@@ -245,6 +245,29 @@ int sst_dsp_boot(struct sst_dsp *sst)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_boot);
|
||||
|
||||
int sst_dsp_wake(struct sst_dsp *sst)
|
||||
{
|
||||
if (sst->ops->wake)
|
||||
return sst->ops->wake(sst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_wake);
|
||||
|
||||
void sst_dsp_sleep(struct sst_dsp *sst)
|
||||
{
|
||||
if (sst->ops->sleep)
|
||||
sst->ops->sleep(sst);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_sleep);
|
||||
|
||||
void sst_dsp_stall(struct sst_dsp *sst)
|
||||
{
|
||||
if (sst->ops->stall)
|
||||
sst->ops->stall(sst);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_stall);
|
||||
|
||||
void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg)
|
||||
{
|
||||
sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY);
|
||||
@@ -352,6 +375,7 @@ struct sst_dsp *sst_dsp_new(struct device *dev,
|
||||
INIT_LIST_HEAD(&sst->free_block_list);
|
||||
INIT_LIST_HEAD(&sst->module_list);
|
||||
INIT_LIST_HEAD(&sst->fw_list);
|
||||
INIT_LIST_HEAD(&sst->scratch_block_list);
|
||||
|
||||
/* Initialise SST Audio DSP */
|
||||
if (sst->ops->init) {
|
||||
@@ -366,6 +390,10 @@ struct sst_dsp *sst_dsp_new(struct device *dev,
|
||||
if (err)
|
||||
goto irq_err;
|
||||
|
||||
err = sst_dma_new(sst);
|
||||
if (err)
|
||||
dev_warn(dev, "sst_dma_new failed %d\n", err);
|
||||
|
||||
return sst;
|
||||
|
||||
irq_err:
|
||||
@@ -381,6 +409,9 @@ void sst_dsp_free(struct sst_dsp *sst)
|
||||
free_irq(sst->irq, sst);
|
||||
if (sst->ops->free)
|
||||
sst->ops->free(sst);
|
||||
|
||||
if (sst->dma)
|
||||
sst_dma_free(sst->dma);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sst_dsp_free);
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
#define SST_DMA_TYPE_DW 1
|
||||
#define SST_DMA_TYPE_MID 2
|
||||
|
||||
/* autosuspend delay 5s*/
|
||||
#define SST_RUNTIME_SUSPEND_DELAY (5 * 1000)
|
||||
|
||||
/* SST Shim register map
|
||||
* The register naming can differ between products. Some products also
|
||||
* contain extra functionality.
|
||||
@@ -156,12 +159,18 @@
|
||||
#define SST_VDRTCTL3 0xaC
|
||||
|
||||
/* VDRTCTL0 */
|
||||
#define SST_VDRTCL0_APLLSE_MASK 1
|
||||
#define SST_VDRTCL0_DSRAMPGE_SHIFT 16
|
||||
#define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT)
|
||||
#define SST_VDRTCL0_ISRAMPGE_SHIFT 6
|
||||
#define SST_VDRTCL0_D3PGD (1 << 0)
|
||||
#define SST_VDRTCL0_D3SRAMPGD (1 << 1)
|
||||
#define SST_VDRTCL0_DSRAMPGE_SHIFT 12
|
||||
#define SST_VDRTCL0_DSRAMPGE_MASK (0xfffff << SST_VDRTCL0_DSRAMPGE_SHIFT)
|
||||
#define SST_VDRTCL0_ISRAMPGE_SHIFT 2
|
||||
#define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT)
|
||||
|
||||
/* VDRTCTL2 */
|
||||
#define SST_VDRTCL2_DCLCGE (1 << 1)
|
||||
#define SST_VDRTCL2_DTCGE (1 << 10)
|
||||
#define SST_VDRTCL2_APLLSE_MASK (1 << 31)
|
||||
|
||||
/* PMCS */
|
||||
#define SST_PMCS 0x84
|
||||
#define SST_PMCS_PS_MASK 0x3
|
||||
@@ -245,6 +254,17 @@ void sst_memcpy_fromio_32(struct sst_dsp *sst,
|
||||
/* DSP reset & boot */
|
||||
void sst_dsp_reset(struct sst_dsp *sst);
|
||||
int sst_dsp_boot(struct sst_dsp *sst);
|
||||
int sst_dsp_wake(struct sst_dsp *sst);
|
||||
void sst_dsp_sleep(struct sst_dsp *sst);
|
||||
void sst_dsp_stall(struct sst_dsp *sst);
|
||||
|
||||
/* DMA */
|
||||
int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id);
|
||||
void sst_dsp_dma_put_channel(struct sst_dsp *dsp);
|
||||
int sst_dsp_dma_copyfrom(struct sst_dsp *sst, dma_addr_t dest_addr,
|
||||
dma_addr_t src_addr, size_t size);
|
||||
int sst_dsp_dma_copyto(struct sst_dsp *sst, dma_addr_t dest_addr,
|
||||
dma_addr_t src_addr, size_t size);
|
||||
|
||||
/* Msg IO */
|
||||
void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg);
|
||||
|
||||
+763
-180
File diff suppressed because it is too large
Load Diff
@@ -42,6 +42,10 @@
|
||||
#define SST_LP_SHIM_OFFSET 0xE7000
|
||||
#define SST_WPT_IRAM_OFFSET 0xA0000
|
||||
#define SST_LP_IRAM_OFFSET 0x80000
|
||||
#define SST_WPT_DSP_DRAM_OFFSET 0x400000
|
||||
#define SST_WPT_DSP_IRAM_OFFSET 0x00000
|
||||
#define SST_LPT_DSP_DRAM_OFFSET 0x400000
|
||||
#define SST_LPT_DSP_IRAM_OFFSET 0x00000
|
||||
|
||||
#define SST_SHIM_PM_REG 0x84
|
||||
|
||||
@@ -86,9 +90,8 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
|
||||
{
|
||||
struct dma_block_info *block;
|
||||
struct sst_module *mod;
|
||||
struct sst_module_data block_data;
|
||||
struct sst_module_template template;
|
||||
int count;
|
||||
int count, ret;
|
||||
void __iomem *ram;
|
||||
|
||||
/* TODO: allowed module types need to be configurable */
|
||||
@@ -109,13 +112,9 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
|
||||
|
||||
memset(&template, 0, sizeof(template));
|
||||
template.id = module->type;
|
||||
template.entry = module->entry_point;
|
||||
template.p.size = module->info.persistent_size;
|
||||
template.p.type = SST_MEM_DRAM;
|
||||
template.p.data_type = SST_DATA_P;
|
||||
template.s.size = module->info.scratch_size;
|
||||
template.s.type = SST_MEM_DRAM;
|
||||
template.s.data_type = SST_DATA_S;
|
||||
template.entry = module->entry_point - 4;
|
||||
template.persistent_size = module->info.persistent_size;
|
||||
template.scratch_size = module->info.scratch_size;
|
||||
|
||||
mod = sst_module_new(fw, &template, NULL);
|
||||
if (mod == NULL)
|
||||
@@ -135,14 +134,14 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
|
||||
switch (block->type) {
|
||||
case SST_HSW_IRAM:
|
||||
ram = dsp->addr.lpe;
|
||||
block_data.offset =
|
||||
mod->offset =
|
||||
block->ram_offset + dsp->addr.iram_offset;
|
||||
block_data.type = SST_MEM_IRAM;
|
||||
mod->type = SST_MEM_IRAM;
|
||||
break;
|
||||
case SST_HSW_DRAM:
|
||||
ram = dsp->addr.lpe;
|
||||
block_data.offset = block->ram_offset;
|
||||
block_data.type = SST_MEM_DRAM;
|
||||
mod->offset = block->ram_offset;
|
||||
mod->type = SST_MEM_DRAM;
|
||||
break;
|
||||
default:
|
||||
dev_err(dsp->dev, "error: bad type 0x%x for block 0x%x\n",
|
||||
@@ -151,30 +150,34 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
block_data.size = block->size;
|
||||
block_data.data_type = SST_DATA_M;
|
||||
block_data.data = (void *)block + sizeof(*block);
|
||||
block_data.data_offset = block_data.data - fw->dma_buf;
|
||||
mod->size = block->size;
|
||||
mod->data = (void *)block + sizeof(*block);
|
||||
mod->data_offset = mod->data - fw->dma_buf;
|
||||
|
||||
dev_dbg(dsp->dev, "copy firmware block %d type 0x%x "
|
||||
dev_dbg(dsp->dev, "module block %d type 0x%x "
|
||||
"size 0x%x ==> ram %p offset 0x%x\n",
|
||||
count, block->type, block->size, ram,
|
||||
count, mod->type, block->size, ram,
|
||||
block->ram_offset);
|
||||
|
||||
sst_module_insert_fixed_block(mod, &block_data);
|
||||
ret = sst_module_alloc_blocks(mod);
|
||||
if (ret < 0) {
|
||||
dev_err(dsp->dev, "error: could not allocate blocks for module %d\n",
|
||||
count);
|
||||
sst_module_free(mod);
|
||||
return ret;
|
||||
}
|
||||
|
||||
block = (void *)block + sizeof(*block) + block->size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hsw_parse_fw_image(struct sst_fw *sst_fw)
|
||||
{
|
||||
struct fw_header *header;
|
||||
struct sst_module *scratch;
|
||||
struct fw_module_header *module;
|
||||
struct sst_dsp *dsp = sst_fw->dsp;
|
||||
struct sst_hsw *hsw = sst_fw->private;
|
||||
int ret, count;
|
||||
|
||||
/* Read the header information from the data pointer */
|
||||
@@ -204,12 +207,8 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw)
|
||||
module = (void *)module + sizeof(*module) + module->mod_size;
|
||||
}
|
||||
|
||||
/* allocate persistent/scratch mem regions */
|
||||
scratch = sst_mem_block_alloc_scratch(dsp);
|
||||
if (scratch == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
sst_hsw_set_scratch_module(hsw, scratch);
|
||||
/* allocate scratch mem regions */
|
||||
sst_block_alloc_scratch(dsp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -248,8 +247,94 @@ static irqreturn_t hsw_irq(int irq, void *context)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void hsw_boot(struct sst_dsp *sst)
|
||||
static void hsw_set_dsp_D3(struct sst_dsp *sst)
|
||||
{
|
||||
u32 val;
|
||||
u32 reg;
|
||||
|
||||
/* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
|
||||
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
|
||||
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
|
||||
/* enable power gating and switch off DRAM & IRAM blocks */
|
||||
val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
|
||||
val |= SST_VDRTCL0_DSRAMPGE_MASK |
|
||||
SST_VDRTCL0_ISRAMPGE_MASK;
|
||||
val &= ~(SST_VDRTCL0_D3PGD | SST_VDRTCL0_D3SRAMPGD);
|
||||
writel(val, sst->addr.pci_cfg + SST_VDRTCTL0);
|
||||
|
||||
/* switch off audio PLL */
|
||||
val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
val |= SST_VDRTCL2_APLLSE_MASK;
|
||||
writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
|
||||
/* disable MCLK(clkctl.smos = 0) */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
|
||||
SST_CLKCTL_MASK, 0);
|
||||
|
||||
/* Set D3 state, delay 50 us */
|
||||
val = readl(sst->addr.pci_cfg + SST_PMCS);
|
||||
val |= SST_PMCS_PS_MASK;
|
||||
writel(val, sst->addr.pci_cfg + SST_PMCS);
|
||||
udelay(50);
|
||||
|
||||
/* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
|
||||
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
|
||||
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
|
||||
udelay(50);
|
||||
|
||||
}
|
||||
|
||||
static void hsw_reset(struct sst_dsp *sst)
|
||||
{
|
||||
/* put DSP into reset and stall */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
|
||||
SST_CSR_RST | SST_CSR_STALL,
|
||||
SST_CSR_RST | SST_CSR_STALL);
|
||||
|
||||
/* keep in reset for 10ms */
|
||||
mdelay(10);
|
||||
|
||||
/* take DSP out of reset and keep stalled for FW loading */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
|
||||
SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
|
||||
}
|
||||
|
||||
static int hsw_set_dsp_D0(struct sst_dsp *sst)
|
||||
{
|
||||
int tries = 10;
|
||||
u32 reg;
|
||||
|
||||
/* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
|
||||
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
|
||||
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
|
||||
/* Disable D3PG (VDRTCTL0.D3PGD = 1) */
|
||||
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
|
||||
reg |= SST_VDRTCL0_D3PGD;
|
||||
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
|
||||
|
||||
/* Set D0 state */
|
||||
reg = readl(sst->addr.pci_cfg + SST_PMCS);
|
||||
reg &= ~SST_PMCS_PS_MASK;
|
||||
writel(reg, sst->addr.pci_cfg + SST_PMCS);
|
||||
|
||||
/* check that ADSP shim is enabled */
|
||||
while (tries--) {
|
||||
reg = readl(sst->addr.pci_cfg + SST_PMCS) & SST_PMCS_PS_MASK;
|
||||
if (reg == 0)
|
||||
goto finish;
|
||||
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
|
||||
finish:
|
||||
/* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
|
||||
SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0);
|
||||
@@ -264,34 +349,96 @@ static void hsw_boot(struct sst_dsp *sst)
|
||||
SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0,
|
||||
SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0);
|
||||
|
||||
/* Stall and reset core, set CSR */
|
||||
hsw_reset(sst);
|
||||
|
||||
/* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
|
||||
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
|
||||
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
|
||||
udelay(50);
|
||||
|
||||
/* switch on audio PLL */
|
||||
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
reg &= ~SST_VDRTCL2_APLLSE_MASK;
|
||||
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
|
||||
/* set default power gating control, enable power gating control for all blocks. that is,
|
||||
can't be accessed, please enable each block before accessing. */
|
||||
reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
|
||||
reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK;
|
||||
writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
|
||||
|
||||
|
||||
/* disable DMA finish function for SSP0 & SSP1 */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1,
|
||||
SST_CSR2_SDFD_SSP1);
|
||||
|
||||
/* enable DMA engine 0,1 all channels to access host memory */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_HMDC,
|
||||
SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff),
|
||||
SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff));
|
||||
/* set on-demond mode on engine 0,1 for all channels */
|
||||
sst_dsp_shim_update_bits(sst, SST_HMDC,
|
||||
SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH,
|
||||
SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH);
|
||||
|
||||
/* disable all clock gating */
|
||||
writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
/* Enable Interrupt from both sides */
|
||||
sst_dsp_shim_update_bits(sst, SST_IMRX, (SST_IMRX_BUSY | SST_IMRX_DONE),
|
||||
0x0);
|
||||
sst_dsp_shim_update_bits(sst, SST_IMRD, (SST_IMRD_DONE | SST_IMRD_BUSY |
|
||||
SST_IMRD_SSP0 | SST_IMRD_DMAC), 0x0);
|
||||
|
||||
/* clear IPC registers */
|
||||
sst_dsp_shim_write(sst, SST_IPCX, 0x0);
|
||||
sst_dsp_shim_write(sst, SST_IPCD, 0x0);
|
||||
sst_dsp_shim_write(sst, 0x80, 0x6);
|
||||
sst_dsp_shim_write(sst, 0xe0, 0x300a);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hsw_boot(struct sst_dsp *sst)
|
||||
{
|
||||
/* set oportunistic mode on engine 0,1 for all channels */
|
||||
sst_dsp_shim_update_bits(sst, SST_HMDC,
|
||||
SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH, 0);
|
||||
|
||||
/* set DSP to RUN */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0);
|
||||
}
|
||||
|
||||
static void hsw_reset(struct sst_dsp *sst)
|
||||
static void hsw_stall(struct sst_dsp *sst)
|
||||
{
|
||||
/* stall DSP */
|
||||
sst_dsp_shim_update_bits(sst, SST_CSR,
|
||||
SST_CSR_24MHZ_LPCS | SST_CSR_STALL,
|
||||
SST_CSR_STALL | SST_CSR_24MHZ_LPCS);
|
||||
}
|
||||
|
||||
static void hsw_sleep(struct sst_dsp *sst)
|
||||
{
|
||||
dev_dbg(sst->dev, "HSW_PM dsp runtime suspend\n");
|
||||
|
||||
/* put DSP into reset and stall */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
|
||||
SST_CSR_RST | SST_CSR_STALL, SST_CSR_RST | SST_CSR_STALL);
|
||||
sst_dsp_shim_update_bits(sst, SST_CSR,
|
||||
SST_CSR_24MHZ_LPCS | SST_CSR_RST | SST_CSR_STALL,
|
||||
SST_CSR_RST | SST_CSR_STALL | SST_CSR_24MHZ_LPCS);
|
||||
|
||||
/* keep in reset for 10ms */
|
||||
mdelay(10);
|
||||
hsw_set_dsp_D3(sst);
|
||||
dev_dbg(sst->dev, "HSW_PM dsp runtime suspend exit\n");
|
||||
}
|
||||
|
||||
/* take DSP out of reset and keep stalled for FW loading */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
|
||||
SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
|
||||
static int hsw_wake(struct sst_dsp *sst)
|
||||
{
|
||||
int ret;
|
||||
|
||||
dev_dbg(sst->dev, "HSW_PM dsp runtime resume\n");
|
||||
|
||||
ret = hsw_set_dsp_D0(sst);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_dbg(sst->dev, "HSW_PM dsp runtime resume exit\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sst_adsp_memregion {
|
||||
@@ -396,6 +543,11 @@ static int hsw_block_enable(struct sst_mem_block *block)
|
||||
dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n",
|
||||
block->type, block->index, block->offset);
|
||||
|
||||
/* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
|
||||
val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
val &= ~SST_VDRTCL2_DCLCGE;
|
||||
writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
|
||||
val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
|
||||
bit = hsw_block_get_bit(block);
|
||||
writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0);
|
||||
@@ -403,6 +555,13 @@ static int hsw_block_enable(struct sst_mem_block *block)
|
||||
/* wait 18 DSP clock ticks */
|
||||
udelay(10);
|
||||
|
||||
/* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
|
||||
val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
val |= SST_VDRTCL2_DCLCGE;
|
||||
writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
|
||||
udelay(50);
|
||||
|
||||
/*add a dummy read before the SRAM block is written, otherwise the writing may miss bytes sometimes.*/
|
||||
sst_mem_block_dummy_read(block);
|
||||
return 0;
|
||||
@@ -420,10 +579,26 @@ static int hsw_block_disable(struct sst_mem_block *block)
|
||||
dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n",
|
||||
block->type, block->index, block->offset);
|
||||
|
||||
/* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
|
||||
val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
val &= ~SST_VDRTCL2_DCLCGE;
|
||||
writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
|
||||
|
||||
val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
|
||||
bit = hsw_block_get_bit(block);
|
||||
writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
|
||||
|
||||
/* wait 18 DSP clock ticks */
|
||||
udelay(10);
|
||||
|
||||
/* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
|
||||
val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
val |= SST_VDRTCL2_DCLCGE;
|
||||
writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
|
||||
|
||||
udelay(50);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -432,27 +607,6 @@ static struct sst_block_ops sst_hsw_ops = {
|
||||
.disable = hsw_block_disable,
|
||||
};
|
||||
|
||||
static int hsw_enable_shim(struct sst_dsp *sst)
|
||||
{
|
||||
int tries = 10;
|
||||
u32 reg;
|
||||
|
||||
/* enable shim */
|
||||
reg = readl(sst->addr.pci_cfg + SST_SHIM_PM_REG);
|
||||
writel(reg & ~0x3, sst->addr.pci_cfg + SST_SHIM_PM_REG);
|
||||
|
||||
/* check that ADSP shim is enabled */
|
||||
while (tries--) {
|
||||
reg = sst_dsp_shim_read_unlocked(sst, SST_CSR);
|
||||
if (reg != 0xffffffff)
|
||||
return 0;
|
||||
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
|
||||
{
|
||||
const struct sst_adsp_memregion *region;
|
||||
@@ -467,12 +621,16 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
|
||||
region = lp_region;
|
||||
region_count = ARRAY_SIZE(lp_region);
|
||||
sst->addr.iram_offset = SST_LP_IRAM_OFFSET;
|
||||
sst->addr.dsp_iram_offset = SST_LPT_DSP_IRAM_OFFSET;
|
||||
sst->addr.dsp_dram_offset = SST_LPT_DSP_DRAM_OFFSET;
|
||||
sst->addr.shim_offset = SST_LP_SHIM_OFFSET;
|
||||
break;
|
||||
case SST_DEV_ID_WILDCAT_POINT:
|
||||
region = wpt_region;
|
||||
region_count = ARRAY_SIZE(wpt_region);
|
||||
sst->addr.iram_offset = SST_WPT_IRAM_OFFSET;
|
||||
sst->addr.dsp_iram_offset = SST_WPT_DSP_IRAM_OFFSET;
|
||||
sst->addr.dsp_dram_offset = SST_WPT_DSP_DRAM_OFFSET;
|
||||
sst->addr.shim_offset = SST_WPT_SHIM_OFFSET;
|
||||
break;
|
||||
default:
|
||||
@@ -487,7 +645,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
|
||||
}
|
||||
|
||||
/* enable the DSP SHIM */
|
||||
ret = hsw_enable_shim(sst);
|
||||
ret = hsw_set_dsp_D0(sst);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n");
|
||||
return ret;
|
||||
@@ -497,10 +655,6 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable Interrupt from both sides */
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, 0x3, 0x0);
|
||||
sst_dsp_shim_update_bits_unlocked(sst, SST_IMRD,
|
||||
(0x3 | 0x1 << 16 | 0x3 << 21), 0x0);
|
||||
|
||||
/* register DSP memory blocks - ideally we should get this from ACPI */
|
||||
for (i = 0; i < region_count; i++) {
|
||||
@@ -532,6 +686,9 @@ static void hsw_free(struct sst_dsp *sst)
|
||||
struct sst_ops haswell_ops = {
|
||||
.reset = hsw_reset,
|
||||
.boot = hsw_boot,
|
||||
.stall = hsw_stall,
|
||||
.wake = hsw_wake,
|
||||
.sleep = hsw_sleep,
|
||||
.write = sst_shim32_write,
|
||||
.read = sst_shim32_read,
|
||||
.write64 = sst_shim32_write64,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,8 +21,10 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define SST_HSW_NO_CHANNELS 2
|
||||
#define SST_HSW_NO_CHANNELS 4
|
||||
#define SST_HSW_MAX_DX_REGIONS 14
|
||||
#define SST_HSW_DX_CONTEXT_SIZE (640 * 1024)
|
||||
#define SST_HSW_CHANNELS_ALL 0xffffffff
|
||||
|
||||
#define SST_HSW_FW_LOG_CONFIG_DWORDS 12
|
||||
#define SST_HSW_GLOBAL_LOG 15
|
||||
@@ -40,6 +42,7 @@ struct sst_hsw_stream;
|
||||
struct sst_hsw_log_stream;
|
||||
struct sst_pdata;
|
||||
struct sst_module;
|
||||
struct sst_module_runtime;
|
||||
extern struct sst_ops haswell_ops;
|
||||
|
||||
/* Stream Allocate Path ID */
|
||||
@@ -84,6 +87,7 @@ enum sst_hsw_device_mclk {
|
||||
enum sst_hsw_device_mode {
|
||||
SST_HSW_DEVICE_CLOCK_SLAVE = 0,
|
||||
SST_HSW_DEVICE_CLOCK_MASTER = 1,
|
||||
SST_HSW_DEVICE_TDM_CLOCK_MASTER = 2,
|
||||
};
|
||||
|
||||
/* DX Power State */
|
||||
@@ -295,7 +299,8 @@ struct sst_hsw_ipc_device_config_req {
|
||||
u32 clock_frequency;
|
||||
u32 mode;
|
||||
u16 clock_divider;
|
||||
u16 reserved;
|
||||
u8 channels;
|
||||
u8 reserved;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Audio Data formats */
|
||||
@@ -430,8 +435,7 @@ int sst_hsw_stream_set_map_config(struct sst_hsw *hsw,
|
||||
int sst_hsw_stream_set_style(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
|
||||
enum sst_hsw_interleaving style);
|
||||
int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
|
||||
struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id,
|
||||
u32 entry_point);
|
||||
struct sst_hsw_stream *stream, struct sst_module_runtime *runtime);
|
||||
int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
|
||||
struct sst_hsw_stream *stream, u32 offset, u32 size);
|
||||
int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
|
||||
@@ -484,7 +488,16 @@ int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item,
|
||||
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);
|
||||
void sst_hsw_set_scratch_module(struct sst_hsw *hsw,
|
||||
struct sst_module *scratch);
|
||||
|
||||
/* runtime module management */
|
||||
struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw,
|
||||
int mod_id, int offset);
|
||||
void sst_hsw_runtime_module_free(struct sst_module_runtime *runtime);
|
||||
|
||||
/* PM */
|
||||
int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw);
|
||||
int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw);
|
||||
int sst_hsw_dsp_load(struct sst_hsw *hsw);
|
||||
int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user