aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/intel
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/intel')
-rw-r--r--sound/soc/intel/Kconfig42
-rw-r--r--sound/soc/intel/Makefile27
-rw-r--r--sound/soc/intel/byt-rt5640.c187
-rw-r--r--sound/soc/intel/haswell.c235
-rw-r--r--sound/soc/intel/mfld_machine.c108
-rw-r--r--sound/soc/intel/sst-acpi.c284
-rw-r--r--sound/soc/intel/sst-baytrail-dsp.c372
-rw-r--r--sound/soc/intel/sst-baytrail-ipc.c867
-rw-r--r--sound/soc/intel/sst-baytrail-ipc.h69
-rw-r--r--sound/soc/intel/sst-baytrail-pcm.c422
-rw-r--r--sound/soc/intel/sst-dsp-priv.h309
-rw-r--r--sound/soc/intel/sst-dsp.c385
-rw-r--r--sound/soc/intel/sst-dsp.h233
-rw-r--r--sound/soc/intel/sst-firmware.c587
-rw-r--r--sound/soc/intel/sst-haswell-dsp.c517
-rw-r--r--sound/soc/intel/sst-haswell-ipc.c1785
-rw-r--r--sound/soc/intel/sst-haswell-ipc.h488
-rw-r--r--sound/soc/intel/sst-haswell-pcm.c872
-rw-r--r--sound/soc/intel/sst-mfld-dsp.h (renamed from sound/soc/intel/sst_dsp.h)8
-rw-r--r--sound/soc/intel/sst-mfld-platform.c (renamed from sound/soc/intel/sst_platform.c)8
-rw-r--r--sound/soc/intel/sst-mfld-platform.h (renamed from sound/soc/intel/sst_platform.h)4
21 files changed, 7745 insertions, 64 deletions
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 61c10bf503d2..3c81b3891209 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -2,12 +2,50 @@ config SND_MFLD_MACHINE
2 tristate "SOC Machine Audio driver for Intel Medfield MID platform" 2 tristate "SOC Machine Audio driver for Intel Medfield MID platform"
3 depends on INTEL_SCU_IPC 3 depends on INTEL_SCU_IPC
4 select SND_SOC_SN95031 4 select SND_SOC_SN95031
5 select SND_SST_PLATFORM 5 select SND_SST_MFLD_PLATFORM
6 help 6 help
7 This adds support for ASoC machine driver for Intel(R) MID Medfield platform 7 This adds support for ASoC machine driver for Intel(R) MID Medfield platform
8 used as alsa device in audio substem in Intel(R) MID devices 8 used as alsa device in audio substem in Intel(R) MID devices
9 Say Y if you have such a device 9 Say Y if you have such a device
10 If unsure select "N". 10 If unsure select "N".
11 11
12config SND_SST_PLATFORM 12config SND_SST_MFLD_PLATFORM
13 tristate 13 tristate
14
15config SND_SOC_INTEL_SST
16 tristate "ASoC support for Intel(R) Smart Sound Technology"
17 select SND_SOC_INTEL_SST_ACPI if ACPI
18 depends on (X86 || COMPILE_TEST)
19 help
20 This adds support for Intel(R) Smart Sound Technology (SST).
21 Say Y if you have such a device
22 If unsure select "N".
23
24config SND_SOC_INTEL_SST_ACPI
25 tristate
26
27config SND_SOC_INTEL_HASWELL
28 tristate
29
30config SND_SOC_INTEL_BAYTRAIL
31 tristate
32
33config SND_SOC_INTEL_HASWELL_MACH
34 tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
35 depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C
36 select SND_SOC_INTEL_HASWELL
37 select SND_SOC_RT5640
38 help
39 This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell
40 Ultrabook platforms.
41 Say Y if you have such a device
42 If unsure select "N".
43
44config SND_SOC_INTEL_BYT_RT5640_MACH
45 tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
46 depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C
47 select SND_SOC_INTEL_BAYTRAIL
48 select SND_SOC_RT5640
49 help
50 This adds audio driver for Intel Baytrail platform based boards
51 with the RT5640 audio codec.
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index 639883339465..edeb79ae3dff 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -1,5 +1,28 @@
1snd-soc-sst-platform-objs := sst_platform.o 1# Core support
2snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o
3snd-soc-sst-acpi-objs := sst-acpi.o
4
5snd-soc-sst-mfld-platform-objs := sst-mfld-platform.o
2snd-soc-mfld-machine-objs := mfld_machine.o 6snd-soc-mfld-machine-objs := mfld_machine.o
3 7
4obj-$(CONFIG_SND_SST_PLATFORM) += snd-soc-sst-platform.o 8obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o
5obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o 9obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o
10
11obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o
12obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
13
14# Platform Support
15snd-soc-sst-haswell-pcm-objs := \
16 sst-haswell-ipc.o sst-haswell-pcm.o sst-haswell-dsp.o
17snd-soc-sst-baytrail-pcm-objs := \
18 sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o
19
20obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += snd-soc-sst-haswell-pcm.o
21obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o
22
23# Machine support
24snd-soc-sst-haswell-objs := haswell.o
25snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
26
27obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
28obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c
new file mode 100644
index 000000000000..eff97c8e5218
--- /dev/null
+++ b/sound/soc/intel/byt-rt5640.c
@@ -0,0 +1,187 @@
1/*
2 * Intel Baytrail SST RT5640 machine driver
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/acpi.h>
19#include <linux/device.h>
20#include <linux/slab.h>
21#include <sound/pcm.h>
22#include <sound/pcm_params.h>
23#include <sound/soc.h>
24#include <sound/jack.h>
25#include "../codecs/rt5640.h"
26
27#include "sst-dsp.h"
28
29static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
30 SND_SOC_DAPM_HP("Headphone", NULL),
31 SND_SOC_DAPM_MIC("Headset Mic", NULL),
32 SND_SOC_DAPM_MIC("Internal Mic", NULL),
33 SND_SOC_DAPM_SPK("Speaker", NULL),
34};
35
36static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
37 {"IN2P", NULL, "Headset Mic"},
38 {"IN2N", NULL, "Headset Mic"},
39 {"DMIC1", NULL, "Internal Mic"},
40 {"Headphone", NULL, "HPOL"},
41 {"Headphone", NULL, "HPOR"},
42 {"Speaker", NULL, "SPOLP"},
43 {"Speaker", NULL, "SPOLN"},
44 {"Speaker", NULL, "SPORP"},
45 {"Speaker", NULL, "SPORN"},
46};
47
48static const struct snd_kcontrol_new byt_rt5640_controls[] = {
49 SOC_DAPM_PIN_SWITCH("Headphone"),
50 SOC_DAPM_PIN_SWITCH("Headset Mic"),
51 SOC_DAPM_PIN_SWITCH("Internal Mic"),
52 SOC_DAPM_PIN_SWITCH("Speaker"),
53};
54
55static int byt_rt5640_hw_params(struct snd_pcm_substream *substream,
56 struct snd_pcm_hw_params *params)
57{
58 struct snd_soc_pcm_runtime *rtd = substream->private_data;
59 struct snd_soc_dai *codec_dai = rtd->codec_dai;
60 int ret;
61
62 ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
63 params_rate(params) * 256,
64 SND_SOC_CLOCK_IN);
65 if (ret < 0) {
66 dev_err(codec_dai->dev, "can't set codec clock %d\n", ret);
67 return ret;
68 }
69 ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1,
70 params_rate(params) * 64,
71 params_rate(params) * 256);
72 if (ret < 0) {
73 dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret);
74 return ret;
75 }
76 return 0;
77}
78
79static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
80{
81 int ret;
82 struct snd_soc_codec *codec = runtime->codec;
83 struct snd_soc_dapm_context *dapm = &codec->dapm;
84 struct snd_soc_card *card = runtime->card;
85
86 card->dapm.idle_bias_off = true;
87
88 ret = snd_soc_add_card_controls(card, byt_rt5640_controls,
89 ARRAY_SIZE(byt_rt5640_controls));
90 if (ret) {
91 dev_err(card->dev, "unable to add card controls\n");
92 return ret;
93 }
94
95 snd_soc_dapm_ignore_suspend(dapm, "HPOL");
96 snd_soc_dapm_ignore_suspend(dapm, "HPOR");
97
98 snd_soc_dapm_ignore_suspend(dapm, "SPOLP");
99 snd_soc_dapm_ignore_suspend(dapm, "SPOLN");
100 snd_soc_dapm_ignore_suspend(dapm, "SPORP");
101 snd_soc_dapm_ignore_suspend(dapm, "SPORN");
102
103 snd_soc_dapm_enable_pin(dapm, "Headset Mic");
104 snd_soc_dapm_enable_pin(dapm, "Headphone");
105 snd_soc_dapm_enable_pin(dapm, "Speaker");
106 snd_soc_dapm_enable_pin(dapm, "Internal Mic");
107
108 snd_soc_dapm_sync(dapm);
109 return ret;
110}
111
112static struct snd_soc_ops byt_rt5640_ops = {
113 .hw_params = byt_rt5640_hw_params,
114};
115
116static struct snd_soc_dai_link byt_rt5640_dais[] = {
117 {
118 .name = "Baytrail Audio",
119 .stream_name = "Audio",
120 .cpu_dai_name = "Front-cpu-dai",
121 .codec_dai_name = "rt5640-aif1",
122 .codec_name = "i2c-10EC5640:00",
123 .platform_name = "baytrail-pcm-audio",
124 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
125 SND_SOC_DAIFMT_CBS_CFS,
126 .init = byt_rt5640_init,
127 .ignore_suspend = 1,
128 .ops = &byt_rt5640_ops,
129 },
130 {
131 .name = "Baytrail Voice",
132 .stream_name = "Voice",
133 .cpu_dai_name = "Mic1-cpu-dai",
134 .codec_dai_name = "rt5640-aif1",
135 .codec_name = "i2c-10EC5640:00",
136 .platform_name = "baytrail-pcm-audio",
137 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
138 SND_SOC_DAIFMT_CBS_CFS,
139 .init = NULL,
140 .ignore_suspend = 1,
141 .ops = &byt_rt5640_ops,
142 },
143};
144
145static struct snd_soc_card byt_rt5640_card = {
146 .name = "byt-rt5640",
147 .dai_link = byt_rt5640_dais,
148 .num_links = ARRAY_SIZE(byt_rt5640_dais),
149 .dapm_widgets = byt_rt5640_widgets,
150 .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
151 .dapm_routes = byt_rt5640_audio_map,
152 .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
153};
154
155static int byt_rt5640_probe(struct platform_device *pdev)
156{
157 struct snd_soc_card *card = &byt_rt5640_card;
158 struct device *dev = &pdev->dev;
159
160 card->dev = &pdev->dev;
161 dev_set_drvdata(dev, card);
162 return snd_soc_register_card(card);
163}
164
165static int byt_rt5640_remove(struct platform_device *pdev)
166{
167 struct snd_soc_card *card = platform_get_drvdata(pdev);
168
169 snd_soc_unregister_card(card);
170
171 return 0;
172}
173
174static struct platform_driver byt_rt5640_audio = {
175 .probe = byt_rt5640_probe,
176 .remove = byt_rt5640_remove,
177 .driver = {
178 .name = "byt-rt5640",
179 .owner = THIS_MODULE,
180 },
181};
182module_platform_driver(byt_rt5640_audio)
183
184MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver");
185MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula");
186MODULE_LICENSE("GPL v2");
187MODULE_ALIAS("platform:byt-rt5640");
diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c
new file mode 100644
index 000000000000..54345a2a7386
--- /dev/null
+++ b/sound/soc/intel/haswell.c
@@ -0,0 +1,235 @@
1/*
2 * Intel Haswell Lynxpoint SST Audio
3 *
4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/platform_device.h>
19#include <sound/core.h>
20#include <sound/pcm.h>
21#include <sound/soc.h>
22#include <sound/pcm_params.h>
23
24#include "sst-dsp.h"
25#include "sst-haswell-ipc.h"
26
27#include "../codecs/rt5640.h"
28
29/* Haswell ULT platforms have a Headphone and Mic jack */
30static const struct snd_soc_dapm_widget haswell_widgets[] = {
31 SND_SOC_DAPM_HP("Headphones", NULL),
32 SND_SOC_DAPM_MIC("Mic", NULL),
33};
34
35static const struct snd_soc_dapm_route haswell_rt5640_map[] = {
36
37 {"Headphones", NULL, "HPOR"},
38 {"Headphones", NULL, "HPOL"},
39 {"IN2P", NULL, "Mic"},
40
41 /* CODEC BE connections */
42 {"SSP0 CODEC IN", NULL, "AIF1 Capture"},
43 {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
44};
45
46static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
47 struct snd_pcm_hw_params *params)
48{
49 struct snd_interval *rate = hw_param_interval(params,
50 SNDRV_PCM_HW_PARAM_RATE);
51 struct snd_interval *channels = hw_param_interval(params,
52 SNDRV_PCM_HW_PARAM_CHANNELS);
53
54 /* The ADSP will covert the FE rate to 48k, stereo */
55 rate->min = rate->max = 48000;
56 channels->min = channels->max = 2;
57
58 /* set SSP0 to 16 bit */
59 snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
60 SNDRV_PCM_HW_PARAM_FIRST_MASK],
61 SNDRV_PCM_FORMAT_S16_LE);
62 return 0;
63}
64
65static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream,
66 struct snd_pcm_hw_params *params)
67{
68 struct snd_soc_pcm_runtime *rtd = substream->private_data;
69 struct snd_soc_dai *codec_dai = rtd->codec_dai;
70 int ret;
71
72 ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000,
73 SND_SOC_CLOCK_IN);
74
75 if (ret < 0) {
76 dev_err(rtd->dev, "can't set codec sysclk configuration\n");
77 return ret;
78 }
79
80 /* set correct codec filter for DAI format and clock config */
81 snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000);
82
83 return ret;
84}
85
86static struct snd_soc_ops haswell_rt5640_ops = {
87 .hw_params = haswell_rt5640_hw_params,
88};
89
90static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd)
91{
92 struct snd_soc_codec *codec = rtd->codec;
93 struct snd_soc_dapm_context *dapm = &codec->dapm;
94 struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
95 struct sst_hsw *haswell = pdata->dsp;
96 int ret;
97
98 /* Set ADSP SSP port settings */
99 ret = sst_hsw_device_set_config(haswell, SST_HSW_DEVICE_SSP_0,
100 SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
101 SST_HSW_DEVICE_CLOCK_MASTER, 9);
102 if (ret < 0) {
103 dev_err(rtd->dev, "failed to set device config\n");
104 return ret;
105 }
106
107 /* always connected */
108 snd_soc_dapm_enable_pin(dapm, "Headphones");
109 snd_soc_dapm_enable_pin(dapm, "Mic");
110
111 return 0;
112}
113
114static struct snd_soc_dai_link haswell_rt5640_dais[] = {
115 /* Front End DAI links */
116 {
117 .name = "System",
118 .stream_name = "System Playback",
119 .cpu_dai_name = "System Pin",
120 .platform_name = "haswell-pcm-audio",
121 .dynamic = 1,
122 .codec_name = "snd-soc-dummy",
123 .codec_dai_name = "snd-soc-dummy-dai",
124 .init = haswell_rtd_init,
125 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
126 .dpcm_playback = 1,
127 },
128 {
129 .name = "Offload0",
130 .stream_name = "Offload0 Playback",
131 .cpu_dai_name = "Offload0 Pin",
132 .platform_name = "haswell-pcm-audio",
133 .dynamic = 1,
134 .codec_name = "snd-soc-dummy",
135 .codec_dai_name = "snd-soc-dummy-dai",
136 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
137 .dpcm_playback = 1,
138 },
139 {
140 .name = "Offload1",
141 .stream_name = "Offload1 Playback",
142 .cpu_dai_name = "Offload1 Pin",
143 .platform_name = "haswell-pcm-audio",
144 .dynamic = 1,
145 .codec_name = "snd-soc-dummy",
146 .codec_dai_name = "snd-soc-dummy-dai",
147 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
148 .dpcm_playback = 1,
149 },
150 {
151 .name = "Loopback",
152 .stream_name = "Loopback",
153 .cpu_dai_name = "Loopback Pin",
154 .platform_name = "haswell-pcm-audio",
155 .dynamic = 0,
156 .codec_name = "snd-soc-dummy",
157 .codec_dai_name = "snd-soc-dummy-dai",
158 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
159 .dpcm_capture = 1,
160 },
161 {
162 .name = "Capture",
163 .stream_name = "Capture",
164 .cpu_dai_name = "Capture Pin",
165 .platform_name = "haswell-pcm-audio",
166 .dynamic = 1,
167 .codec_name = "snd-soc-dummy",
168 .codec_dai_name = "snd-soc-dummy-dai",
169 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
170 .dpcm_capture = 1,
171 },
172
173 /* Back End DAI links */
174 {
175 /* SSP0 - Codec */
176 .name = "Codec",
177 .be_id = 0,
178 .cpu_dai_name = "snd-soc-dummy-dai",
179 .platform_name = "snd-soc-dummy",
180 .no_pcm = 1,
181 .codec_name = "i2c-INT33CA:00",
182 .codec_dai_name = "rt5640-aif1",
183 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
184 SND_SOC_DAIFMT_CBS_CFS,
185 .ignore_suspend = 1,
186 .ignore_pmdown_time = 1,
187 .be_hw_params_fixup = haswell_ssp0_fixup,
188 .ops = &haswell_rt5640_ops,
189 .dpcm_playback = 1,
190 .dpcm_capture = 1,
191 },
192};
193
194/* audio machine driver for Haswell Lynxpoint DSP + RT5640 */
195static struct snd_soc_card haswell_rt5640 = {
196 .name = "haswell-rt5640",
197 .owner = THIS_MODULE,
198 .dai_link = haswell_rt5640_dais,
199 .num_links = ARRAY_SIZE(haswell_rt5640_dais),
200 .dapm_widgets = haswell_widgets,
201 .num_dapm_widgets = ARRAY_SIZE(haswell_widgets),
202 .dapm_routes = haswell_rt5640_map,
203 .num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map),
204 .fully_routed = true,
205};
206
207static int haswell_audio_probe(struct platform_device *pdev)
208{
209 haswell_rt5640.dev = &pdev->dev;
210
211 return snd_soc_register_card(&haswell_rt5640);
212}
213
214static int haswell_audio_remove(struct platform_device *pdev)
215{
216 snd_soc_unregister_card(&haswell_rt5640);
217 return 0;
218}
219
220static struct platform_driver haswell_audio = {
221 .probe = haswell_audio_probe,
222 .remove = haswell_audio_remove,
223 .driver = {
224 .name = "haswell-audio",
225 .owner = THIS_MODULE,
226 },
227};
228
229module_platform_driver(haswell_audio)
230
231/* Module information */
232MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
233MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint");
234MODULE_LICENSE("GPL v2");
235MODULE_ALIAS("platform:haswell-audio");
diff --git a/sound/soc/intel/mfld_machine.c b/sound/soc/intel/mfld_machine.c
index d3d4c32434f7..031d78783fc8 100644
--- a/sound/soc/intel/mfld_machine.c
+++ b/sound/soc/intel/mfld_machine.c
@@ -53,6 +53,7 @@ enum soc_mic_bias_zones {
53 53
54static unsigned int hs_switch; 54static unsigned int hs_switch;
55static unsigned int lo_dac; 55static unsigned int lo_dac;
56static struct snd_soc_codec *mfld_codec;
56 57
57struct mfld_mc_private { 58struct mfld_mc_private {
58 void __iomem *int_base; 59 void __iomem *int_base;
@@ -100,40 +101,47 @@ static int headset_get_switch(struct snd_kcontrol *kcontrol,
100static int headset_set_switch(struct snd_kcontrol *kcontrol, 101static int headset_set_switch(struct snd_kcontrol *kcontrol,
101 struct snd_ctl_elem_value *ucontrol) 102 struct snd_ctl_elem_value *ucontrol)
102{ 103{
103 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 104 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
105 struct snd_soc_dapm_context *dapm = &card->dapm;
104 106
105 if (ucontrol->value.integer.value[0] == hs_switch) 107 if (ucontrol->value.integer.value[0] == hs_switch)
106 return 0; 108 return 0;
107 109
110 snd_soc_dapm_mutex_lock(dapm);
111
108 if (ucontrol->value.integer.value[0]) { 112 if (ucontrol->value.integer.value[0]) {
109 pr_debug("hs_set HS path\n"); 113 pr_debug("hs_set HS path\n");
110 snd_soc_dapm_enable_pin(&codec->dapm, "Headphones"); 114 snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
111 snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); 115 snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
112 } else { 116 } else {
113 pr_debug("hs_set EP path\n"); 117 pr_debug("hs_set EP path\n");
114 snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); 118 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
115 snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT"); 119 snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
116 } 120 }
117 snd_soc_dapm_sync(&codec->dapm); 121
122 snd_soc_dapm_sync_unlocked(dapm);
123
124 snd_soc_dapm_mutex_unlock(dapm);
125
118 hs_switch = ucontrol->value.integer.value[0]; 126 hs_switch = ucontrol->value.integer.value[0];
119 127
120 return 0; 128 return 0;
121} 129}
122 130
123static void lo_enable_out_pins(struct snd_soc_codec *codec) 131static void lo_enable_out_pins(struct snd_soc_dapm_context *dapm)
124{ 132{
125 snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTL"); 133 snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL");
126 snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTR"); 134 snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR");
127 snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTL"); 135 snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL");
128 snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTR"); 136 snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTR");
129 snd_soc_dapm_enable_pin(&codec->dapm, "VIB1OUT"); 137 snd_soc_dapm_enable_pin_unlocked(dapm, "VIB1OUT");
130 snd_soc_dapm_enable_pin(&codec->dapm, "VIB2OUT"); 138 snd_soc_dapm_enable_pin_unlocked(dapm, "VIB2OUT");
131 if (hs_switch) { 139 if (hs_switch) {
132 snd_soc_dapm_enable_pin(&codec->dapm, "Headphones"); 140 snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones");
133 snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); 141 snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
134 } else { 142 } else {
135 snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); 143 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
136 snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT"); 144 snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT");
137 } 145 }
138} 146}
139 147
@@ -147,45 +155,53 @@ static int lo_get_switch(struct snd_kcontrol *kcontrol,
147static int lo_set_switch(struct snd_kcontrol *kcontrol, 155static int lo_set_switch(struct snd_kcontrol *kcontrol,
148 struct snd_ctl_elem_value *ucontrol) 156 struct snd_ctl_elem_value *ucontrol)
149{ 157{
150 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 158 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
159 struct snd_soc_dapm_context *dapm = &card->dapm;
151 160
152 if (ucontrol->value.integer.value[0] == lo_dac) 161 if (ucontrol->value.integer.value[0] == lo_dac)
153 return 0; 162 return 0;
154 163
164 snd_soc_dapm_mutex_lock(dapm);
165
155 /* we dont want to work with last state of lineout so just enable all 166 /* we dont want to work with last state of lineout so just enable all
156 * pins and then disable pins not required 167 * pins and then disable pins not required
157 */ 168 */
158 lo_enable_out_pins(codec); 169 lo_enable_out_pins(dapm);
170
159 switch (ucontrol->value.integer.value[0]) { 171 switch (ucontrol->value.integer.value[0]) {
160 case 0: 172 case 0:
161 pr_debug("set vibra path\n"); 173 pr_debug("set vibra path\n");
162 snd_soc_dapm_disable_pin(&codec->dapm, "VIB1OUT"); 174 snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT");
163 snd_soc_dapm_disable_pin(&codec->dapm, "VIB2OUT"); 175 snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT");
164 snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0); 176 snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0);
165 break; 177 break;
166 178
167 case 1: 179 case 1:
168 pr_debug("set hs path\n"); 180 pr_debug("set hs path\n");
169 snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); 181 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones");
170 snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); 182 snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT");
171 snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22); 183 snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x22);
172 break; 184 break;
173 185
174 case 2: 186 case 2:
175 pr_debug("set spkr path\n"); 187 pr_debug("set spkr path\n");
176 snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTL"); 188 snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL");
177 snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTR"); 189 snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR");
178 snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44); 190 snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x44);
179 break; 191 break;
180 192
181 case 3: 193 case 3:
182 pr_debug("set null path\n"); 194 pr_debug("set null path\n");
183 snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTL"); 195 snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL");
184 snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTR"); 196 snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR");
185 snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66); 197 snd_soc_update_bits(mfld_codec, SN95031_LOCTL, 0x66, 0x66);
186 break; 198 break;
187 } 199 }
188 snd_soc_dapm_sync(&codec->dapm); 200
201 snd_soc_dapm_sync_unlocked(dapm);
202
203 snd_soc_dapm_mutex_unlock(dapm);
204
189 lo_dac = ucontrol->value.integer.value[0]; 205 lo_dac = ucontrol->value.integer.value[0];
190 return 0; 206 return 0;
191} 207}
@@ -221,26 +237,11 @@ static void mfld_jack_check(unsigned int intr_status)
221 237
222static int mfld_init(struct snd_soc_pcm_runtime *runtime) 238static int mfld_init(struct snd_soc_pcm_runtime *runtime)
223{ 239{
224 struct snd_soc_codec *codec = runtime->codec; 240 struct snd_soc_dapm_context *dapm = &runtime->card->dapm;
225 struct snd_soc_dapm_context *dapm = &codec->dapm;
226 int ret_val; 241 int ret_val;
227 242
228 /* Add jack sense widgets */ 243 mfld_codec = runtime->codec;
229 snd_soc_dapm_new_controls(dapm, mfld_widgets, ARRAY_SIZE(mfld_widgets));
230
231 /* Set up the map */
232 snd_soc_dapm_add_routes(dapm, mfld_map, ARRAY_SIZE(mfld_map));
233 244
234 /* always connected */
235 snd_soc_dapm_enable_pin(dapm, "Headphones");
236 snd_soc_dapm_enable_pin(dapm, "Mic");
237
238 ret_val = snd_soc_add_codec_controls(codec, mfld_snd_controls,
239 ARRAY_SIZE(mfld_snd_controls));
240 if (ret_val) {
241 pr_err("soc_add_controls failed %d", ret_val);
242 return ret_val;
243 }
244 /* default is earpiece pin, userspace sets it explcitly */ 245 /* default is earpiece pin, userspace sets it explcitly */
245 snd_soc_dapm_disable_pin(dapm, "Headphones"); 246 snd_soc_dapm_disable_pin(dapm, "Headphones");
246 /* default is lineout NC, userspace sets it explcitly */ 247 /* default is lineout NC, userspace sets it explcitly */
@@ -253,7 +254,7 @@ static int mfld_init(struct snd_soc_pcm_runtime *runtime)
253 snd_soc_dapm_disable_pin(dapm, "LINEINR"); 254 snd_soc_dapm_disable_pin(dapm, "LINEINR");
254 255
255 /* Headset and button jack detection */ 256 /* Headset and button jack detection */
256 ret_val = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack", 257 ret_val = snd_soc_jack_new(mfld_codec, "Intel(R) MID Audio Jack",
257 SND_JACK_HEADSET | SND_JACK_BTN_0 | 258 SND_JACK_HEADSET | SND_JACK_BTN_0 |
258 SND_JACK_BTN_1, &mfld_jack); 259 SND_JACK_BTN_1, &mfld_jack);
259 if (ret_val) { 260 if (ret_val) {
@@ -335,6 +336,13 @@ static struct snd_soc_card snd_soc_card_mfld = {
335 .owner = THIS_MODULE, 336 .owner = THIS_MODULE,
336 .dai_link = mfld_msic_dailink, 337 .dai_link = mfld_msic_dailink,
337 .num_links = ARRAY_SIZE(mfld_msic_dailink), 338 .num_links = ARRAY_SIZE(mfld_msic_dailink),
339
340 .controls = mfld_snd_controls,
341 .num_controls = ARRAY_SIZE(mfld_snd_controls),
342 .dapm_widgets = mfld_widgets,
343 .num_dapm_widgets = ARRAY_SIZE(mfld_widgets),
344 .dapm_routes = mfld_map,
345 .num_dapm_routes = ARRAY_SIZE(mfld_map),
338}; 346};
339 347
340static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev) 348static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev)
diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c
new file mode 100644
index 000000000000..5d06eecb6198
--- /dev/null
+++ b/sound/soc/intel/sst-acpi.c
@@ -0,0 +1,284 @@
1/*
2 * Intel SST loader on ACPI systems
3 *
4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/acpi.h>
18#include <linux/device.h>
19#include <linux/firmware.h>
20#include <linux/module.h>
21#include <linux/platform_device.h>
22
23#include "sst-dsp.h"
24
25#define SST_LPT_DSP_DMA_ADDR_OFFSET 0x0F0000
26#define SST_WPT_DSP_DMA_ADDR_OFFSET 0x0FE000
27#define SST_LPT_DSP_DMA_SIZE (1024 - 1)
28
29/* Descriptor for SST ASoC machine driver */
30struct sst_acpi_mach {
31 /* ACPI ID for the matching machine driver. Audio codec for instance */
32 const u8 id[ACPI_ID_LEN];
33 /* machine driver name */
34 const char *drv_name;
35 /* firmware file name */
36 const char *fw_filename;
37};
38
39/* Descriptor for setting up SST platform data */
40struct sst_acpi_desc {
41 const char *drv_name;
42 struct sst_acpi_mach *machines;
43 /* Platform resource indexes. Must set to -1 if not used */
44 int resindex_lpe_base;
45 int resindex_pcicfg_base;
46 int resindex_fw_base;
47 int irqindex_host_ipc;
48 int resindex_dma_base;
49 /* Unique number identifying the SST core on platform */
50 int sst_id;
51 /* DMA only valid when resindex_dma_base != -1*/
52 int dma_engine;
53 int dma_size;
54};
55
56struct sst_acpi_priv {
57 struct platform_device *pdev_mach;
58 struct platform_device *pdev_pcm;
59 struct sst_pdata sst_pdata;
60 struct sst_acpi_desc *desc;
61 struct sst_acpi_mach *mach;
62};
63
64static void sst_acpi_fw_cb(const struct firmware *fw, void *context)
65{
66 struct platform_device *pdev = context;
67 struct device *dev = &pdev->dev;
68 struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
69 struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
70 struct sst_acpi_desc *desc = sst_acpi->desc;
71 struct sst_acpi_mach *mach = sst_acpi->mach;
72
73 sst_pdata->fw = fw;
74 if (!fw) {
75 dev_err(dev, "Cannot load firmware %s\n", mach->fw_filename);
76 return;
77 }
78
79 /* register PCM and DAI driver */
80 sst_acpi->pdev_pcm =
81 platform_device_register_data(dev, desc->drv_name, -1,
82 sst_pdata, sizeof(*sst_pdata));
83 if (IS_ERR(sst_acpi->pdev_pcm)) {
84 dev_err(dev, "Cannot register device %s. Error %d\n",
85 desc->drv_name, (int)PTR_ERR(sst_acpi->pdev_pcm));
86 }
87
88 return;
89}
90
91static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
92 void *context, void **ret)
93{
94 *(bool *)context = true;
95 return AE_OK;
96}
97
98static struct sst_acpi_mach *sst_acpi_find_machine(
99 struct sst_acpi_mach *machines)
100{
101 struct sst_acpi_mach *mach;
102 bool found = false;
103
104 for (mach = machines; mach->id[0]; mach++)
105 if (ACPI_SUCCESS(acpi_get_devices(mach->id,
106 sst_acpi_mach_match,
107 &found, NULL)) && found)
108 return mach;
109
110 return NULL;
111}
112
113static int sst_acpi_probe(struct platform_device *pdev)
114{
115 const struct acpi_device_id *id;
116 struct device *dev = &pdev->dev;
117 struct sst_acpi_priv *sst_acpi;
118 struct sst_pdata *sst_pdata;
119 struct sst_acpi_mach *mach;
120 struct sst_acpi_desc *desc;
121 struct resource *mmio;
122 int ret = 0;
123
124 sst_acpi = devm_kzalloc(dev, sizeof(*sst_acpi), GFP_KERNEL);
125 if (sst_acpi == NULL)
126 return -ENOMEM;
127
128 id = acpi_match_device(dev->driver->acpi_match_table, dev);
129 if (!id)
130 return -ENODEV;
131
132 desc = (struct sst_acpi_desc *)id->driver_data;
133 mach = sst_acpi_find_machine(desc->machines);
134 if (mach == NULL) {
135 dev_err(dev, "No matching ASoC machine driver found\n");
136 return -ENODEV;
137 }
138
139 sst_pdata = &sst_acpi->sst_pdata;
140 sst_pdata->id = desc->sst_id;
141 sst_acpi->desc = desc;
142 sst_acpi->mach = mach;
143
144 if (desc->resindex_dma_base >= 0) {
145 sst_pdata->dma_engine = desc->dma_engine;
146 sst_pdata->dma_base = desc->resindex_dma_base;
147 sst_pdata->dma_size = desc->dma_size;
148 }
149
150 if (desc->irqindex_host_ipc >= 0)
151 sst_pdata->irq = platform_get_irq(pdev, desc->irqindex_host_ipc);
152
153 if (desc->resindex_lpe_base >= 0) {
154 mmio = platform_get_resource(pdev, IORESOURCE_MEM,
155 desc->resindex_lpe_base);
156 if (mmio) {
157 sst_pdata->lpe_base = mmio->start;
158 sst_pdata->lpe_size = resource_size(mmio);
159 }
160 }
161
162 if (desc->resindex_pcicfg_base >= 0) {
163 mmio = platform_get_resource(pdev, IORESOURCE_MEM,
164 desc->resindex_pcicfg_base);
165 if (mmio) {
166 sst_pdata->pcicfg_base = mmio->start;
167 sst_pdata->pcicfg_size = resource_size(mmio);
168 }
169 }
170
171 if (desc->resindex_fw_base >= 0) {
172 mmio = platform_get_resource(pdev, IORESOURCE_MEM,
173 desc->resindex_fw_base);
174 if (mmio) {
175 sst_pdata->fw_base = mmio->start;
176 sst_pdata->fw_size = resource_size(mmio);
177 }
178 }
179
180 platform_set_drvdata(pdev, sst_acpi);
181
182 /* register machine driver */
183 sst_acpi->pdev_mach =
184 platform_device_register_data(dev, mach->drv_name, -1,
185 sst_pdata, sizeof(*sst_pdata));
186 if (IS_ERR(sst_acpi->pdev_mach))
187 return PTR_ERR(sst_acpi->pdev_mach);
188
189 /* continue SST probing after firmware is loaded */
190 ret = request_firmware_nowait(THIS_MODULE, true, mach->fw_filename,
191 dev, GFP_KERNEL, pdev, sst_acpi_fw_cb);
192 if (ret)
193 platform_device_unregister(sst_acpi->pdev_mach);
194
195 return ret;
196}
197
198static int sst_acpi_remove(struct platform_device *pdev)
199{
200 struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev);
201 struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata;
202
203 platform_device_unregister(sst_acpi->pdev_mach);
204 if (!IS_ERR_OR_NULL(sst_acpi->pdev_pcm))
205 platform_device_unregister(sst_acpi->pdev_pcm);
206 release_firmware(sst_pdata->fw);
207
208 return 0;
209}
210
211static struct sst_acpi_mach haswell_machines[] = {
212 { "INT33CA", "haswell-audio", "intel/IntcSST1.bin" },
213 {}
214};
215
216static struct sst_acpi_desc sst_acpi_haswell_desc = {
217 .drv_name = "haswell-pcm-audio",
218 .machines = haswell_machines,
219 .resindex_lpe_base = 0,
220 .resindex_pcicfg_base = 1,
221 .resindex_fw_base = -1,
222 .irqindex_host_ipc = 0,
223 .sst_id = SST_DEV_ID_LYNX_POINT,
224 .dma_engine = SST_DMA_TYPE_DW,
225 .resindex_dma_base = SST_LPT_DSP_DMA_ADDR_OFFSET,
226 .dma_size = SST_LPT_DSP_DMA_SIZE,
227};
228
229static struct sst_acpi_mach broadwell_machines[] = {
230 { "INT343A", "broadwell-audio", "intel/IntcSST2.bin" },
231 {}
232};
233
234static struct sst_acpi_desc sst_acpi_broadwell_desc = {
235 .drv_name = "haswell-pcm-audio",
236 .machines = broadwell_machines,
237 .resindex_lpe_base = 0,
238 .resindex_pcicfg_base = 1,
239 .resindex_fw_base = -1,
240 .irqindex_host_ipc = 0,
241 .sst_id = SST_DEV_ID_WILDCAT_POINT,
242 .dma_engine = SST_DMA_TYPE_DW,
243 .resindex_dma_base = SST_WPT_DSP_DMA_ADDR_OFFSET,
244 .dma_size = SST_LPT_DSP_DMA_SIZE,
245};
246
247static struct sst_acpi_mach baytrail_machines[] = {
248 { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" },
249 {}
250};
251
252static struct sst_acpi_desc sst_acpi_baytrail_desc = {
253 .drv_name = "baytrail-pcm-audio",
254 .machines = baytrail_machines,
255 .resindex_lpe_base = 0,
256 .resindex_pcicfg_base = 1,
257 .resindex_fw_base = 2,
258 .irqindex_host_ipc = 5,
259 .sst_id = SST_DEV_ID_BYT,
260 .resindex_dma_base = -1,
261};
262
263static struct acpi_device_id sst_acpi_match[] = {
264 { "INT33C8", (unsigned long)&sst_acpi_haswell_desc },
265 { "INT3438", (unsigned long)&sst_acpi_broadwell_desc },
266 { "80860F28", (unsigned long)&sst_acpi_baytrail_desc },
267 { }
268};
269MODULE_DEVICE_TABLE(acpi, sst_acpi_match);
270
271static struct platform_driver sst_acpi_driver = {
272 .probe = sst_acpi_probe,
273 .remove = sst_acpi_remove,
274 .driver = {
275 .name = "sst-acpi",
276 .owner = THIS_MODULE,
277 .acpi_match_table = ACPI_PTR(sst_acpi_match),
278 },
279};
280module_platform_driver(sst_acpi_driver);
281
282MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
283MODULE_DESCRIPTION("Intel SST loader on ACPI systems");
284MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/sst-baytrail-dsp.c
new file mode 100644
index 000000000000..a50bf7fc0e3a
--- /dev/null
+++ b/sound/soc/intel/sst-baytrail-dsp.c
@@ -0,0 +1,372 @@
1/*
2 * Intel Baytrail SST DSP driver
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15#include <linux/delay.h>
16#include <linux/fs.h>
17#include <linux/slab.h>
18#include <linux/device.h>
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/dma-mapping.h>
22#include <linux/platform_device.h>
23#include <linux/firmware.h>
24
25#include "sst-dsp.h"
26#include "sst-dsp-priv.h"
27#include "sst-baytrail-ipc.h"
28
29#define SST_BYT_FW_SIGNATURE_SIZE 4
30#define SST_BYT_FW_SIGN "$SST"
31
32#define SST_BYT_IRAM_OFFSET 0xC0000
33#define SST_BYT_DRAM_OFFSET 0x100000
34#define SST_BYT_SHIM_OFFSET 0x140000
35
36enum sst_ram_type {
37 SST_BYT_IRAM = 1,
38 SST_BYT_DRAM = 2,
39 SST_BYT_CACHE = 3,
40};
41
42struct dma_block_info {
43 enum sst_ram_type type; /* IRAM/DRAM */
44 u32 size; /* Bytes */
45 u32 ram_offset; /* Offset in I/DRAM */
46 u32 rsvd; /* Reserved field */
47};
48
49struct fw_header {
50 unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
51 u32 file_size; /* size of fw minus this header */
52 u32 modules; /* # of modules */
53 u32 file_format; /* version of header format */
54 u32 reserved[4];
55};
56
57struct sst_byt_fw_module_header {
58 unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE];
59 u32 mod_size; /* size of module */
60 u32 blocks; /* # of blocks */
61 u32 type; /* codec type, pp lib */
62 u32 entry_point;
63};
64
65static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
66 struct sst_byt_fw_module_header *module)
67{
68 struct dma_block_info *block;
69 struct sst_module *mod;
70 struct sst_module_data block_data;
71 struct sst_module_template template;
72 int count;
73
74 memset(&template, 0, sizeof(template));
75 template.id = module->type;
76 template.entry = module->entry_point;
77 template.p.type = SST_MEM_DRAM;
78 template.p.data_type = SST_DATA_P;
79 template.s.type = SST_MEM_DRAM;
80 template.s.data_type = SST_DATA_S;
81
82 mod = sst_module_new(fw, &template, NULL);
83 if (mod == NULL)
84 return -ENOMEM;
85
86 block = (void *)module + sizeof(*module);
87
88 for (count = 0; count < module->blocks; count++) {
89
90 if (block->size <= 0) {
91 dev_err(dsp->dev, "block %d size invalid\n", count);
92 return -EINVAL;
93 }
94
95 switch (block->type) {
96 case SST_BYT_IRAM:
97 block_data.offset = block->ram_offset +
98 dsp->addr.iram_offset;
99 block_data.type = SST_MEM_IRAM;
100 break;
101 case SST_BYT_DRAM:
102 block_data.offset = block->ram_offset +
103 dsp->addr.dram_offset;
104 block_data.type = SST_MEM_DRAM;
105 break;
106 case SST_BYT_CACHE:
107 block_data.offset = block->ram_offset +
108 (dsp->addr.fw_ext - dsp->addr.lpe);
109 block_data.type = SST_MEM_CACHE;
110 break;
111 default:
112 dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n",
113 block->type, count);
114 return -EINVAL;
115 }
116
117 block_data.size = block->size;
118 block_data.data_type = SST_DATA_M;
119 block_data.data = (void *)block + sizeof(*block);
120
121 sst_module_insert_fixed_block(mod, &block_data);
122
123 block = (void *)block + sizeof(*block) + block->size;
124 }
125 return 0;
126}
127
128static int sst_byt_parse_fw_image(struct sst_fw *sst_fw)
129{
130 struct fw_header *header;
131 struct sst_byt_fw_module_header *module;
132 struct sst_dsp *dsp = sst_fw->dsp;
133 int ret, count;
134
135 /* Read the header information from the data pointer */
136 header = (struct fw_header *)sst_fw->dma_buf;
137
138 /* verify FW */
139 if ((strncmp(header->signature, SST_BYT_FW_SIGN, 4) != 0) ||
140 (sst_fw->size != header->file_size + sizeof(*header))) {
141 /* Invalid FW signature */
142 dev_err(dsp->dev, "Invalid FW sign/filesize mismatch\n");
143 return -EINVAL;
144 }
145
146 dev_dbg(dsp->dev,
147 "header sign=%4s size=0x%x modules=0x%x fmt=0x%x size=%zu\n",
148 header->signature, header->file_size, header->modules,
149 header->file_format, sizeof(*header));
150
151 module = (void *)sst_fw->dma_buf + sizeof(*header);
152 for (count = 0; count < header->modules; count++) {
153 /* module */
154 ret = sst_byt_parse_module(dsp, sst_fw, module);
155 if (ret < 0) {
156 dev_err(dsp->dev, "invalid module %d\n", count);
157 return ret;
158 }
159 module = (void *)module + sizeof(*module) + module->mod_size;
160 }
161
162 return 0;
163}
164
165static void sst_byt_dump_shim(struct sst_dsp *sst)
166{
167 int i;
168 u64 reg;
169
170 for (i = 0; i <= 0xF0; i += 8) {
171 reg = sst_dsp_shim_read64_unlocked(sst, i);
172 if (reg)
173 dev_dbg(sst->dev, "shim 0x%2.2x value 0x%16.16llx\n",
174 i, reg);
175 }
176
177 for (i = 0x00; i <= 0xff; i += 4) {
178 reg = readl(sst->addr.pci_cfg + i);
179 if (reg)
180 dev_dbg(sst->dev, "pci 0x%2.2x value 0x%8.8x\n",
181 i, (u32)reg);
182 }
183}
184
185static irqreturn_t sst_byt_irq(int irq, void *context)
186{
187 struct sst_dsp *sst = (struct sst_dsp *) context;
188 u64 isrx;
189 irqreturn_t ret = IRQ_NONE;
190
191 spin_lock(&sst->spinlock);
192
193 isrx = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
194 if (isrx & SST_ISRX_DONE) {
195 /* ADSP has processed the message request from IA */
196 sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCX,
197 SST_BYT_IPCX_DONE, 0);
198 ret = IRQ_WAKE_THREAD;
199 }
200 if (isrx & SST_BYT_ISRX_REQUEST) {
201 /* mask message request from ADSP and do processing later */
202 sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
203 SST_BYT_IMRX_REQUEST,
204 SST_BYT_IMRX_REQUEST);
205 ret = IRQ_WAKE_THREAD;
206 }
207
208 spin_unlock(&sst->spinlock);
209
210 return ret;
211}
212
213static void sst_byt_boot(struct sst_dsp *sst)
214{
215 int tries = 10;
216
217 /* release stall and wait to unstall */
218 sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_STALL, 0x0);
219 while (tries--) {
220 if (!(sst_dsp_shim_read64(sst, SST_CSR) &
221 SST_BYT_CSR_PWAITMODE))
222 break;
223 msleep(100);
224 }
225 if (tries < 0) {
226 dev_err(sst->dev, "unable to start DSP\n");
227 sst_byt_dump_shim(sst);
228 }
229}
230
231static void sst_byt_reset(struct sst_dsp *sst)
232{
233 /* put DSP into reset, set reset vector and stall */
234 sst_dsp_shim_update_bits64(sst, SST_CSR,
235 SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL,
236 SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL);
237
238 udelay(10);
239
240 /* take DSP out of reset and keep stalled for FW loading */
241 sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_RST, 0);
242}
243
244struct sst_adsp_memregion {
245 u32 start;
246 u32 end;
247 int blocks;
248 enum sst_mem_type type;
249};
250
251/* BYT test stuff */
252static const struct sst_adsp_memregion byt_region[] = {
253 {0xC0000, 0x100000, 8, SST_MEM_IRAM}, /* I-SRAM - 8 * 32kB */
254 {0x100000, 0x140000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
255};
256
257static int sst_byt_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata)
258{
259 sst->addr.lpe_base = pdata->lpe_base;
260 sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size);
261 if (!sst->addr.lpe)
262 return -ENODEV;
263
264 /* ADSP PCI MMIO config space */
265 sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size);
266 if (!sst->addr.pci_cfg) {
267 iounmap(sst->addr.lpe);
268 return -ENODEV;
269 }
270
271 /* SST Extended FW allocation */
272 sst->addr.fw_ext = ioremap(pdata->fw_base, pdata->fw_size);
273 if (!sst->addr.fw_ext) {
274 iounmap(sst->addr.pci_cfg);
275 iounmap(sst->addr.lpe);
276 return -ENODEV;
277 }
278
279 /* SST Shim */
280 sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset;
281
282 sst_dsp_mailbox_init(sst, SST_BYT_MAILBOX_OFFSET + 0x204,
283 SST_BYT_IPC_MAX_PAYLOAD_SIZE,
284 SST_BYT_MAILBOX_OFFSET,
285 SST_BYT_IPC_MAX_PAYLOAD_SIZE);
286
287 sst->irq = pdata->irq;
288
289 return 0;
290}
291
292static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata)
293{
294 const struct sst_adsp_memregion *region;
295 struct device *dev;
296 int ret = -ENODEV, i, j, region_count;
297 u32 offset, size;
298
299 dev = sst->dev;
300
301 switch (sst->id) {
302 case SST_DEV_ID_BYT:
303 region = byt_region;
304 region_count = ARRAY_SIZE(byt_region);
305 sst->addr.iram_offset = SST_BYT_IRAM_OFFSET;
306 sst->addr.dram_offset = SST_BYT_DRAM_OFFSET;
307 sst->addr.shim_offset = SST_BYT_SHIM_OFFSET;
308 break;
309 default:
310 dev_err(dev, "failed to get mem resources\n");
311 return ret;
312 }
313
314 ret = sst_byt_resource_map(sst, pdata);
315 if (ret < 0) {
316 dev_err(dev, "failed to map resources\n");
317 return ret;
318 }
319
320 /*
321 * save the physical address of extended firmware block in the first
322 * 4 bytes of the mailbox
323 */
324 memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET,
325 &pdata->fw_base, sizeof(u32));
326
327 ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
328 if (ret)
329 return ret;
330
331 /* enable Interrupt from both sides */
332 sst_dsp_shim_update_bits64(sst, SST_IMRX, 0x3, 0x0);
333 sst_dsp_shim_update_bits64(sst, SST_IMRD, 0x3, 0x0);
334
335 /* register DSP memory blocks - ideally we should get this from ACPI */
336 for (i = 0; i < region_count; i++) {
337 offset = region[i].start;
338 size = (region[i].end - region[i].start) / region[i].blocks;
339
340 /* register individual memory blocks */
341 for (j = 0; j < region[i].blocks; j++) {
342 sst_mem_block_register(sst, offset, size,
343 region[i].type, NULL, j, sst);
344 offset += size;
345 }
346 }
347
348 return 0;
349}
350
351static void sst_byt_free(struct sst_dsp *sst)
352{
353 sst_mem_block_unregister_all(sst);
354 iounmap(sst->addr.lpe);
355 iounmap(sst->addr.pci_cfg);
356 iounmap(sst->addr.fw_ext);
357}
358
359struct sst_ops sst_byt_ops = {
360 .reset = sst_byt_reset,
361 .boot = sst_byt_boot,
362 .write = sst_shim32_write,
363 .read = sst_shim32_read,
364 .write64 = sst_shim32_write64,
365 .read64 = sst_shim32_read64,
366 .ram_read = sst_memcpy_fromio_32,
367 .ram_write = sst_memcpy_toio_32,
368 .irq_handler = sst_byt_irq,
369 .init = sst_byt_init,
370 .free = sst_byt_free,
371 .parse_fw = sst_byt_parse_fw_image,
372};
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c
new file mode 100644
index 000000000000..d0eaeee21be4
--- /dev/null
+++ b/sound/soc/intel/sst-baytrail-ipc.c
@@ -0,0 +1,867 @@
1/*
2 * Intel Baytrail SST IPC Support
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15#include <linux/types.h>
16#include <linux/kernel.h>
17#include <linux/list.h>
18#include <linux/device.h>
19#include <linux/wait.h>
20#include <linux/spinlock.h>
21#include <linux/workqueue.h>
22#include <linux/export.h>
23#include <linux/slab.h>
24#include <linux/delay.h>
25#include <linux/list.h>
26#include <linux/platform_device.h>
27#include <linux/kthread.h>
28#include <linux/firmware.h>
29#include <linux/io.h>
30#include <asm/div64.h>
31
32#include "sst-baytrail-ipc.h"
33#include "sst-dsp.h"
34#include "sst-dsp-priv.h"
35
36/* IPC message timeout */
37#define IPC_TIMEOUT_MSECS 300
38#define IPC_BOOT_MSECS 200
39
40#define IPC_EMPTY_LIST_SIZE 8
41
42/* IPC header bits */
43#define IPC_HEADER_MSG_ID_MASK 0xff
44#define IPC_HEADER_MSG_ID(x) ((x) & IPC_HEADER_MSG_ID_MASK)
45#define IPC_HEADER_STR_ID_SHIFT 8
46#define IPC_HEADER_STR_ID_MASK 0x1f
47#define IPC_HEADER_STR_ID(x) (((x) & 0x1f) << IPC_HEADER_STR_ID_SHIFT)
48#define IPC_HEADER_LARGE_SHIFT 13
49#define IPC_HEADER_LARGE(x) (((x) & 0x1) << IPC_HEADER_LARGE_SHIFT)
50#define IPC_HEADER_DATA_SHIFT 16
51#define IPC_HEADER_DATA_MASK 0x3fff
52#define IPC_HEADER_DATA(x) (((x) & 0x3fff) << IPC_HEADER_DATA_SHIFT)
53
54/* mask for differentiating between notification and reply message */
55#define IPC_NOTIFICATION (0x1 << 7)
56
57/* I2L Stream config/control msgs */
58#define IPC_IA_ALLOC_STREAM 0x20
59#define IPC_IA_FREE_STREAM 0x21
60#define IPC_IA_PAUSE_STREAM 0x24
61#define IPC_IA_RESUME_STREAM 0x25
62#define IPC_IA_DROP_STREAM 0x26
63#define IPC_IA_START_STREAM 0x30
64
65/* notification messages */
66#define IPC_IA_FW_INIT_CMPLT 0x81
67#define IPC_SST_PERIOD_ELAPSED 0x97
68
69/* IPC messages between host and ADSP */
70struct sst_byt_address_info {
71 u32 addr;
72 u32 size;
73} __packed;
74
75struct sst_byt_str_type {
76 u8 codec_type;
77 u8 str_type;
78 u8 operation;
79 u8 protected_str;
80 u8 time_slots;
81 u8 reserved;
82 u16 result;
83} __packed;
84
85struct sst_byt_pcm_params {
86 u8 num_chan;
87 u8 pcm_wd_sz;
88 u8 use_offload_path;
89 u8 reserved;
90 u32 sfreq;
91 u8 channel_map[8];
92} __packed;
93
94struct sst_byt_frames_info {
95 u16 num_entries;
96 u16 rsrvd;
97 u32 frag_size;
98 struct sst_byt_address_info ring_buf_info[8];
99} __packed;
100
101struct sst_byt_alloc_params {
102 struct sst_byt_str_type str_type;
103 struct sst_byt_pcm_params pcm_params;
104 struct sst_byt_frames_info frame_info;
105} __packed;
106
107struct sst_byt_alloc_response {
108 struct sst_byt_str_type str_type;
109 u8 reserved[88];
110} __packed;
111
112struct sst_byt_start_stream_params {
113 u32 byte_offset;
114} __packed;
115
116struct sst_byt_tstamp {
117 u64 ring_buffer_counter;
118 u64 hardware_counter;
119 u64 frames_decoded;
120 u64 bytes_decoded;
121 u64 bytes_copied;
122 u32 sampling_frequency;
123 u32 channel_peak[8];
124} __packed;
125
126/* driver internal IPC message structure */
127struct ipc_message {
128 struct list_head list;
129 u64 header;
130
131 /* direction wrt host CPU */
132 char tx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE];
133 size_t tx_size;
134 char rx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE];
135 size_t rx_size;
136
137 wait_queue_head_t waitq;
138 bool complete;
139 bool wait;
140 int errno;
141};
142
143struct sst_byt_stream;
144struct sst_byt;
145
146/* stream infomation */
147struct sst_byt_stream {
148 struct list_head node;
149
150 /* configuration */
151 struct sst_byt_alloc_params request;
152 struct sst_byt_alloc_response reply;
153
154 /* runtime info */
155 struct sst_byt *byt;
156 int str_id;
157 bool commited;
158 bool running;
159
160 /* driver callback */
161 u32 (*notify_position)(struct sst_byt_stream *stream, void *data);
162 void *pdata;
163};
164
165/* SST Baytrail IPC data */
166struct sst_byt {
167 struct device *dev;
168 struct sst_dsp *dsp;
169
170 /* stream */
171 struct list_head stream_list;
172
173 /* boot */
174 wait_queue_head_t boot_wait;
175 bool boot_complete;
176
177 /* IPC messaging */
178 struct list_head tx_list;
179 struct list_head rx_list;
180 struct list_head empty_list;
181 wait_queue_head_t wait_txq;
182 struct task_struct *tx_thread;
183 struct kthread_worker kworker;
184 struct kthread_work kwork;
185 struct ipc_message *msg;
186};
187
188static inline u64 sst_byt_header(int msg_id, int data, bool large, int str_id)
189{
190 u64 header;
191
192 header = IPC_HEADER_MSG_ID(msg_id) |
193 IPC_HEADER_STR_ID(str_id) |
194 IPC_HEADER_LARGE(large) |
195 IPC_HEADER_DATA(data) |
196 SST_BYT_IPCX_BUSY;
197
198 return header;
199}
200
201static inline u16 sst_byt_header_msg_id(u64 header)
202{
203 return header & IPC_HEADER_MSG_ID_MASK;
204}
205
206static inline u8 sst_byt_header_str_id(u64 header)
207{
208 return (header >> IPC_HEADER_STR_ID_SHIFT) & IPC_HEADER_STR_ID_MASK;
209}
210
211static inline u16 sst_byt_header_data(u64 header)
212{
213 return (header >> IPC_HEADER_DATA_SHIFT) & IPC_HEADER_DATA_MASK;
214}
215
216static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt,
217 int stream_id)
218{
219 struct sst_byt_stream *stream;
220
221 list_for_each_entry(stream, &byt->stream_list, node) {
222 if (stream->str_id == stream_id)
223 return stream;
224 }
225
226 return NULL;
227}
228
229static void sst_byt_ipc_shim_dbg(struct sst_byt *byt, const char *text)
230{
231 struct sst_dsp *sst = byt->dsp;
232 u64 isr, ipcd, imrx, ipcx;
233
234 ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX);
235 isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX);
236 ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
237 imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX);
238
239 dev_err(byt->dev,
240 "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n",
241 text, ipcx, isr, ipcd, imrx);
242}
243
244/* locks held by caller */
245static struct ipc_message *sst_byt_msg_get_empty(struct sst_byt *byt)
246{
247 struct ipc_message *msg = NULL;
248
249 if (!list_empty(&byt->empty_list)) {
250 msg = list_first_entry(&byt->empty_list,
251 struct ipc_message, list);
252 list_del(&msg->list);
253 }
254
255 return msg;
256}
257
258static void sst_byt_ipc_tx_msgs(struct kthread_work *work)
259{
260 struct sst_byt *byt =
261 container_of(work, struct sst_byt, kwork);
262 struct ipc_message *msg;
263 u64 ipcx;
264 unsigned long flags;
265
266 spin_lock_irqsave(&byt->dsp->spinlock, flags);
267 if (list_empty(&byt->tx_list)) {
268 spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
269 return;
270 }
271
272 /* if the DSP is busy we will TX messages after IRQ */
273 ipcx = sst_dsp_shim_read64_unlocked(byt->dsp, SST_IPCX);
274 if (ipcx & SST_BYT_IPCX_BUSY) {
275 spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
276 return;
277 }
278
279 msg = list_first_entry(&byt->tx_list, struct ipc_message, list);
280
281 list_move(&msg->list, &byt->rx_list);
282
283 /* send the message */
284 if (msg->header & IPC_HEADER_LARGE(true))
285 sst_dsp_outbox_write(byt->dsp, msg->tx_data, msg->tx_size);
286 sst_dsp_shim_write64_unlocked(byt->dsp, SST_IPCX, msg->header);
287
288 spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
289}
290
291static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt,
292 struct ipc_message *msg)
293{
294 msg->complete = true;
295
296 if (!msg->wait)
297 list_add_tail(&msg->list, &byt->empty_list);
298 else
299 wake_up(&msg->waitq);
300}
301
302static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg,
303 void *rx_data)
304{
305 unsigned long flags;
306 int ret;
307
308 /* wait for DSP completion */
309 ret = wait_event_timeout(msg->waitq, msg->complete,
310 msecs_to_jiffies(IPC_TIMEOUT_MSECS));
311
312 spin_lock_irqsave(&byt->dsp->spinlock, flags);
313 if (ret == 0) {
314 list_del(&msg->list);
315 sst_byt_ipc_shim_dbg(byt, "message timeout");
316
317 ret = -ETIMEDOUT;
318 } else {
319
320 /* copy the data returned from DSP */
321 if (msg->rx_size)
322 memcpy(rx_data, msg->rx_data, msg->rx_size);
323 ret = msg->errno;
324 }
325
326 list_add_tail(&msg->list, &byt->empty_list);
327 spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
328 return ret;
329}
330
331static int sst_byt_ipc_tx_message(struct sst_byt *byt, u64 header,
332 void *tx_data, size_t tx_bytes,
333 void *rx_data, size_t rx_bytes, int wait)
334{
335 unsigned long flags;
336 struct ipc_message *msg;
337
338 spin_lock_irqsave(&byt->dsp->spinlock, flags);
339
340 msg = sst_byt_msg_get_empty(byt);
341 if (msg == NULL) {
342 spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
343 return -EBUSY;
344 }
345
346 msg->header = header;
347 msg->tx_size = tx_bytes;
348 msg->rx_size = rx_bytes;
349 msg->wait = wait;
350 msg->errno = 0;
351 msg->complete = false;
352
353 if (tx_bytes) {
354 /* msg content = lower 32-bit of the header + data */
355 *(u32 *)msg->tx_data = (u32)(header & (u32)-1);
356 memcpy(msg->tx_data + sizeof(u32), tx_data, tx_bytes);
357 msg->tx_size += sizeof(u32);
358 }
359
360 list_add_tail(&msg->list, &byt->tx_list);
361 spin_unlock_irqrestore(&byt->dsp->spinlock, flags);
362
363 queue_kthread_work(&byt->kworker, &byt->kwork);
364
365 if (wait)
366 return sst_byt_tx_wait_done(byt, msg, rx_data);
367 else
368 return 0;
369}
370
371static inline int sst_byt_ipc_tx_msg_wait(struct sst_byt *byt, u64 header,
372 void *tx_data, size_t tx_bytes,
373 void *rx_data, size_t rx_bytes)
374{
375 return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes,
376 rx_data, rx_bytes, 1);
377}
378
379static inline int sst_byt_ipc_tx_msg_nowait(struct sst_byt *byt, u64 header,
380 void *tx_data, size_t tx_bytes)
381{
382 return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes,
383 NULL, 0, 0);
384}
385
386static struct ipc_message *sst_byt_reply_find_msg(struct sst_byt *byt,
387 u64 header)
388{
389 struct ipc_message *msg = NULL, *_msg;
390 u64 mask;
391
392 /* match reply to message sent based on msg and stream IDs */
393 mask = IPC_HEADER_MSG_ID_MASK |
394 IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT;
395 header &= mask;
396
397 if (list_empty(&byt->rx_list)) {
398 dev_err(byt->dev,
399 "ipc: rx list is empty but received 0x%llx\n", header);
400 goto out;
401 }
402
403 list_for_each_entry(_msg, &byt->rx_list, list) {
404 if ((_msg->header & mask) == header) {
405 msg = _msg;
406 break;
407 }
408 }
409
410out:
411 return msg;
412}
413
414static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg)
415{
416 struct sst_byt_stream *stream;
417 u64 header = msg->header;
418 u8 stream_id = sst_byt_header_str_id(header);
419 u8 stream_msg = sst_byt_header_msg_id(header);
420
421 stream = sst_byt_get_stream(byt, stream_id);
422 if (stream == NULL)
423 return;
424
425 switch (stream_msg) {
426 case IPC_IA_DROP_STREAM:
427 case IPC_IA_PAUSE_STREAM:
428 case IPC_IA_FREE_STREAM:
429 stream->running = false;
430 break;
431 case IPC_IA_START_STREAM:
432 case IPC_IA_RESUME_STREAM:
433 stream->running = true;
434 break;
435 }
436}
437
438static int sst_byt_process_reply(struct sst_byt *byt, u64 header)
439{
440 struct ipc_message *msg;
441
442 msg = sst_byt_reply_find_msg(byt, header);
443 if (msg == NULL)
444 return 1;
445
446 if (header & IPC_HEADER_LARGE(true)) {
447 msg->rx_size = sst_byt_header_data(header);
448 sst_dsp_inbox_read(byt->dsp, msg->rx_data, msg->rx_size);
449 }
450
451 /* update any stream states */
452 sst_byt_stream_update(byt, msg);
453
454 list_del(&msg->list);
455 /* wake up */
456 sst_byt_tx_msg_reply_complete(byt, msg);
457
458 return 1;
459}
460
461static void sst_byt_fw_ready(struct sst_byt *byt, u64 header)
462{
463 dev_dbg(byt->dev, "ipc: DSP is ready 0x%llX\n", header);
464
465 byt->boot_complete = true;
466 wake_up(&byt->boot_wait);
467}
468
469static int sst_byt_process_notification(struct sst_byt *byt,
470 unsigned long *flags)
471{
472 struct sst_dsp *sst = byt->dsp;
473 struct sst_byt_stream *stream;
474 u64 header;
475 u8 msg_id, stream_id;
476 int handled = 1;
477
478 header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
479 msg_id = sst_byt_header_msg_id(header);
480
481 switch (msg_id) {
482 case IPC_SST_PERIOD_ELAPSED:
483 stream_id = sst_byt_header_str_id(header);
484 stream = sst_byt_get_stream(byt, stream_id);
485 if (stream && stream->running && stream->notify_position) {
486 spin_unlock_irqrestore(&sst->spinlock, *flags);
487 stream->notify_position(stream, stream->pdata);
488 spin_lock_irqsave(&sst->spinlock, *flags);
489 }
490 break;
491 case IPC_IA_FW_INIT_CMPLT:
492 sst_byt_fw_ready(byt, header);
493 break;
494 }
495
496 return handled;
497}
498
499static irqreturn_t sst_byt_irq_thread(int irq, void *context)
500{
501 struct sst_dsp *sst = (struct sst_dsp *) context;
502 struct sst_byt *byt = sst_dsp_get_thread_context(sst);
503 u64 header;
504 unsigned long flags;
505
506 spin_lock_irqsave(&sst->spinlock, flags);
507
508 header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD);
509 if (header & SST_BYT_IPCD_BUSY) {
510 if (header & IPC_NOTIFICATION) {
511 /* message from ADSP */
512 sst_byt_process_notification(byt, &flags);
513 } else {
514 /* reply from ADSP */
515 sst_byt_process_reply(byt, header);
516 }
517 /*
518 * clear IPCD BUSY bit and set DONE bit. Tell DSP we have
519 * processed the message and can accept new. Clear data part
520 * of the header
521 */
522 sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCD,
523 SST_BYT_IPCD_DONE | SST_BYT_IPCD_BUSY |
524 IPC_HEADER_DATA(IPC_HEADER_DATA_MASK),
525 SST_BYT_IPCD_DONE);
526 /* unmask message request interrupts */
527 sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX,
528 SST_BYT_IMRX_REQUEST, 0);
529 }
530
531 spin_unlock_irqrestore(&sst->spinlock, flags);
532
533 /* continue to send any remaining messages... */
534 queue_kthread_work(&byt->kworker, &byt->kwork);
535
536 return IRQ_HANDLED;
537}
538
539/* stream API */
540struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
541 u32 (*notify_position)(struct sst_byt_stream *stream, void *data),
542 void *data)
543{
544 struct sst_byt_stream *stream;
545
546 stream = kzalloc(sizeof(*stream), GFP_KERNEL);
547 if (stream == NULL)
548 return NULL;
549
550 list_add(&stream->node, &byt->stream_list);
551 stream->notify_position = notify_position;
552 stream->pdata = data;
553 stream->byt = byt;
554 stream->str_id = id;
555
556 return stream;
557}
558
559int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
560 int bits)
561{
562 stream->request.pcm_params.pcm_wd_sz = bits;
563 return 0;
564}
565
566int sst_byt_stream_set_channels(struct sst_byt *byt,
567 struct sst_byt_stream *stream, u8 channels)
568{
569 stream->request.pcm_params.num_chan = channels;
570 return 0;
571}
572
573int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
574 unsigned int rate)
575{
576 stream->request.pcm_params.sfreq = rate;
577 return 0;
578}
579
580/* stream sonfiguration */
581int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
582 int codec_type, int stream_type, int operation)
583{
584 stream->request.str_type.codec_type = codec_type;
585 stream->request.str_type.str_type = stream_type;
586 stream->request.str_type.operation = operation;
587 stream->request.str_type.time_slots = 0xc;
588
589 return 0;
590}
591
592int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
593 uint32_t buffer_addr, uint32_t buffer_size)
594{
595 stream->request.frame_info.num_entries = 1;
596 stream->request.frame_info.ring_buf_info[0].addr = buffer_addr;
597 stream->request.frame_info.ring_buf_info[0].size = buffer_size;
598 /* calculate bytes per 4 ms fragment */
599 stream->request.frame_info.frag_size =
600 stream->request.pcm_params.sfreq *
601 stream->request.pcm_params.num_chan *
602 stream->request.pcm_params.pcm_wd_sz / 8 *
603 4 / 1000;
604 return 0;
605}
606
607int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream)
608{
609 struct sst_byt_alloc_params *str_req = &stream->request;
610 struct sst_byt_alloc_response *reply = &stream->reply;
611 u64 header;
612 int ret;
613
614 header = sst_byt_header(IPC_IA_ALLOC_STREAM,
615 sizeof(*str_req) + sizeof(u32),
616 true, stream->str_id);
617 ret = sst_byt_ipc_tx_msg_wait(byt, header, str_req, sizeof(*str_req),
618 reply, sizeof(*reply));
619 if (ret < 0) {
620 dev_err(byt->dev, "ipc: error stream commit failed\n");
621 return ret;
622 }
623
624 stream->commited = true;
625
626 return 0;
627}
628
629int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream)
630{
631 u64 header;
632 int ret = 0;
633
634 if (!stream->commited)
635 goto out;
636
637 header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id);
638 ret = sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0);
639 if (ret < 0) {
640 dev_err(byt->dev, "ipc: free stream %d failed\n",
641 stream->str_id);
642 return -EAGAIN;
643 }
644
645 stream->commited = false;
646out:
647 list_del(&stream->node);
648 kfree(stream);
649
650 return ret;
651}
652
653static int sst_byt_stream_operations(struct sst_byt *byt, int type,
654 int stream_id, int wait)
655{
656 struct sst_byt_start_stream_params start_stream;
657 u64 header;
658 void *tx_msg = NULL;
659 size_t size = 0;
660
661 if (type != IPC_IA_START_STREAM) {
662 header = sst_byt_header(type, 0, false, stream_id);
663 } else {
664 start_stream.byte_offset = 0;
665 header = sst_byt_header(IPC_IA_START_STREAM,
666 sizeof(start_stream) + sizeof(u32),
667 true, stream_id);
668 tx_msg = &start_stream;
669 size = sizeof(start_stream);
670 }
671
672 if (wait)
673 return sst_byt_ipc_tx_msg_wait(byt, header,
674 tx_msg, size, NULL, 0);
675 else
676 return sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size);
677}
678
679/* stream ALSA trigger operations */
680int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream)
681{
682 int ret;
683
684 ret = sst_byt_stream_operations(byt, IPC_IA_START_STREAM,
685 stream->str_id, 0);
686 if (ret < 0)
687 dev_err(byt->dev, "ipc: error failed to start stream %d\n",
688 stream->str_id);
689
690 return ret;
691}
692
693int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream)
694{
695 int ret;
696
697 /* don't stop streams that are not commited */
698 if (!stream->commited)
699 return 0;
700
701 ret = sst_byt_stream_operations(byt, IPC_IA_DROP_STREAM,
702 stream->str_id, 0);
703 if (ret < 0)
704 dev_err(byt->dev, "ipc: error failed to stop stream %d\n",
705 stream->str_id);
706 return ret;
707}
708
709int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream)
710{
711 int ret;
712
713 ret = sst_byt_stream_operations(byt, IPC_IA_PAUSE_STREAM,
714 stream->str_id, 0);
715 if (ret < 0)
716 dev_err(byt->dev, "ipc: error failed to pause stream %d\n",
717 stream->str_id);
718
719 return ret;
720}
721
722int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream)
723{
724 int ret;
725
726 ret = sst_byt_stream_operations(byt, IPC_IA_RESUME_STREAM,
727 stream->str_id, 0);
728 if (ret < 0)
729 dev_err(byt->dev, "ipc: error failed to resume stream %d\n",
730 stream->str_id);
731
732 return ret;
733}
734
735int sst_byt_get_dsp_position(struct sst_byt *byt,
736 struct sst_byt_stream *stream, int buffer_size)
737{
738 struct sst_dsp *sst = byt->dsp;
739 struct sst_byt_tstamp fw_tstamp;
740 u8 str_id = stream->str_id;
741 u32 tstamp_offset;
742
743 tstamp_offset = SST_BYT_TIMESTAMP_OFFSET + str_id * sizeof(fw_tstamp);
744 memcpy_fromio(&fw_tstamp,
745 sst->addr.lpe + tstamp_offset, sizeof(fw_tstamp));
746
747 return do_div(fw_tstamp.ring_buffer_counter, buffer_size);
748}
749
750static int msg_empty_list_init(struct sst_byt *byt)
751{
752 struct ipc_message *msg;
753 int i;
754
755 byt->msg = kzalloc(sizeof(*msg) * IPC_EMPTY_LIST_SIZE, GFP_KERNEL);
756 if (byt->msg == NULL)
757 return -ENOMEM;
758
759 for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
760 init_waitqueue_head(&byt->msg[i].waitq);
761 list_add(&byt->msg[i].list, &byt->empty_list);
762 }
763
764 return 0;
765}
766
767struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt)
768{
769 return byt->dsp;
770}
771
772static struct sst_dsp_device byt_dev = {
773 .thread = sst_byt_irq_thread,
774 .ops = &sst_byt_ops,
775};
776
777int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata)
778{
779 struct sst_byt *byt;
780 struct sst_fw *byt_sst_fw;
781 int err;
782
783 dev_dbg(dev, "initialising Byt DSP IPC\n");
784
785 byt = devm_kzalloc(dev, sizeof(*byt), GFP_KERNEL);
786 if (byt == NULL)
787 return -ENOMEM;
788
789 byt->dev = dev;
790 INIT_LIST_HEAD(&byt->stream_list);
791 INIT_LIST_HEAD(&byt->tx_list);
792 INIT_LIST_HEAD(&byt->rx_list);
793 INIT_LIST_HEAD(&byt->empty_list);
794 init_waitqueue_head(&byt->boot_wait);
795 init_waitqueue_head(&byt->wait_txq);
796
797 err = msg_empty_list_init(byt);
798 if (err < 0)
799 return -ENOMEM;
800
801 /* start the IPC message thread */
802 init_kthread_worker(&byt->kworker);
803 byt->tx_thread = kthread_run(kthread_worker_fn,
804 &byt->kworker,
805 dev_name(byt->dev));
806 if (IS_ERR(byt->tx_thread)) {
807 err = PTR_ERR(byt->tx_thread);
808 dev_err(byt->dev, "error failed to create message TX task\n");
809 goto err_free_msg;
810 }
811 init_kthread_work(&byt->kwork, sst_byt_ipc_tx_msgs);
812
813 byt_dev.thread_context = byt;
814
815 /* init SST shim */
816 byt->dsp = sst_dsp_new(dev, &byt_dev, pdata);
817 if (byt->dsp == NULL) {
818 err = -ENODEV;
819 goto err_free_msg;
820 }
821
822 /* keep the DSP in reset state for base FW loading */
823 sst_dsp_reset(byt->dsp);
824
825 byt_sst_fw = sst_fw_new(byt->dsp, pdata->fw, byt);
826 if (byt_sst_fw == NULL) {
827 err = -ENODEV;
828 dev_err(dev, "error: failed to load firmware\n");
829 goto fw_err;
830 }
831
832 /* wait for DSP boot completion */
833 sst_dsp_boot(byt->dsp);
834 err = wait_event_timeout(byt->boot_wait, byt->boot_complete,
835 msecs_to_jiffies(IPC_BOOT_MSECS));
836 if (err == 0) {
837 err = -EIO;
838 dev_err(byt->dev, "ipc: error DSP boot timeout\n");
839 goto boot_err;
840 }
841
842 pdata->dsp = byt;
843
844 return 0;
845
846boot_err:
847 sst_dsp_reset(byt->dsp);
848 sst_fw_free(byt_sst_fw);
849fw_err:
850 sst_dsp_free(byt->dsp);
851err_free_msg:
852 kfree(byt->msg);
853
854 return err;
855}
856EXPORT_SYMBOL_GPL(sst_byt_dsp_init);
857
858void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata)
859{
860 struct sst_byt *byt = pdata->dsp;
861
862 sst_dsp_reset(byt->dsp);
863 sst_fw_free_all(byt->dsp);
864 sst_dsp_free(byt->dsp);
865 kfree(byt->msg);
866}
867EXPORT_SYMBOL_GPL(sst_byt_dsp_free);
diff --git a/sound/soc/intel/sst-baytrail-ipc.h b/sound/soc/intel/sst-baytrail-ipc.h
new file mode 100644
index 000000000000..f172b6440fa9
--- /dev/null
+++ b/sound/soc/intel/sst-baytrail-ipc.h
@@ -0,0 +1,69 @@
1/*
2 * Intel Baytrail SST IPC Support
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15#ifndef __SST_BYT_IPC_H
16#define __SST_BYT_IPC_H
17
18#include <linux/types.h>
19
20struct sst_byt;
21struct sst_byt_stream;
22struct sst_pdata;
23extern struct sst_ops sst_byt_ops;
24
25
26#define SST_BYT_MAILBOX_OFFSET 0x144000
27#define SST_BYT_TIMESTAMP_OFFSET (SST_BYT_MAILBOX_OFFSET + 0x800)
28
29/**
30 * Upfront defined maximum message size that is
31 * expected by the in/out communication pipes in FW.
32 */
33#define SST_BYT_IPC_MAX_PAYLOAD_SIZE 200
34
35/* stream API */
36struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id,
37 uint32_t (*get_write_position)(struct sst_byt_stream *stream,
38 void *data),
39 void *data);
40
41/* stream configuration */
42int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream,
43 int bits);
44int sst_byt_stream_set_channels(struct sst_byt *byt,
45 struct sst_byt_stream *stream, u8 channels);
46int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream,
47 unsigned int rate);
48int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream,
49 int codec_type, int stream_type, int operation);
50int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream,
51 uint32_t buffer_addr, uint32_t buffer_size);
52int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream);
53int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream);
54
55/* stream ALSA trigger operations */
56int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream);
57int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream);
58int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream);
59int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream);
60
61int sst_byt_get_dsp_position(struct sst_byt *byt,
62 struct sst_byt_stream *stream, int buffer_size);
63
64/* init */
65int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata);
66void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata);
67struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt);
68
69#endif
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c
new file mode 100644
index 000000000000..6d101f3813b4
--- /dev/null
+++ b/sound/soc/intel/sst-baytrail-pcm.c
@@ -0,0 +1,422 @@
1/*
2 * Intel Baytrail SST PCM Support
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15#include <linux/module.h>
16#include <linux/dma-mapping.h>
17#include <linux/slab.h>
18#include <sound/core.h>
19#include <sound/pcm.h>
20#include <sound/pcm_params.h>
21#include <sound/soc.h>
22#include "sst-baytrail-ipc.h"
23#include "sst-dsp-priv.h"
24#include "sst-dsp.h"
25
26#define BYT_PCM_COUNT 2
27
28static const struct snd_pcm_hardware sst_byt_pcm_hardware = {
29 .info = SNDRV_PCM_INFO_MMAP |
30 SNDRV_PCM_INFO_MMAP_VALID |
31 SNDRV_PCM_INFO_INTERLEAVED |
32 SNDRV_PCM_INFO_PAUSE |
33 SNDRV_PCM_INFO_RESUME,
34 .formats = SNDRV_PCM_FMTBIT_S16_LE |
35 SNDRV_PCM_FORMAT_S24_LE,
36 .period_bytes_min = 384,
37 .period_bytes_max = 48000,
38 .periods_min = 2,
39 .periods_max = 250,
40 .buffer_bytes_max = 96000,
41};
42
43/* private data for each PCM DSP stream */
44struct sst_byt_pcm_data {
45 struct sst_byt_stream *stream;
46 struct snd_pcm_substream *substream;
47 struct mutex mutex;
48};
49
50/* private data for the driver */
51struct sst_byt_priv_data {
52 /* runtime DSP */
53 struct sst_byt *byt;
54
55 /* DAI data */
56 struct sst_byt_pcm_data pcm[BYT_PCM_COUNT];
57};
58
59/* this may get called several times by oss emulation */
60static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream,
61 struct snd_pcm_hw_params *params)
62{
63 struct snd_soc_pcm_runtime *rtd = substream->private_data;
64 struct sst_byt_priv_data *pdata =
65 snd_soc_platform_get_drvdata(rtd->platform);
66 struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
67 struct sst_byt *byt = pdata->byt;
68 u32 rate, bits;
69 u8 channels;
70 int ret, playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
71
72 dev_dbg(rtd->dev, "PCM: hw_params, pcm_data %p\n", pcm_data);
73
74 ret = sst_byt_stream_type(byt, pcm_data->stream,
75 1, 1, !playback);
76 if (ret < 0) {
77 dev_err(rtd->dev, "failed to set stream format %d\n", ret);
78 return ret;
79 }
80
81 rate = params_rate(params);
82 ret = sst_byt_stream_set_rate(byt, pcm_data->stream, rate);
83 if (ret < 0) {
84 dev_err(rtd->dev, "could not set rate %d\n", rate);
85 return ret;
86 }
87
88 bits = snd_pcm_format_width(params_format(params));
89 ret = sst_byt_stream_set_bits(byt, pcm_data->stream, bits);
90 if (ret < 0) {
91 dev_err(rtd->dev, "could not set formats %d\n",
92 params_rate(params));
93 return ret;
94 }
95
96 channels = (u8)(params_channels(params) & 0xF);
97 ret = sst_byt_stream_set_channels(byt, pcm_data->stream, channels);
98 if (ret < 0) {
99 dev_err(rtd->dev, "could not set channels %d\n",
100 params_rate(params));
101 return ret;
102 }
103
104 snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
105
106 ret = sst_byt_stream_buffer(byt, pcm_data->stream,
107 substream->dma_buffer.addr,
108 params_buffer_bytes(params));
109 if (ret < 0) {
110 dev_err(rtd->dev, "PCM: failed to set DMA buffer %d\n", ret);
111 return ret;
112 }
113
114 ret = sst_byt_stream_commit(byt, pcm_data->stream);
115 if (ret < 0) {
116 dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret);
117 return ret;
118 }
119
120 return 0;
121}
122
123static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream)
124{
125 struct snd_soc_pcm_runtime *rtd = substream->private_data;
126
127 dev_dbg(rtd->dev, "PCM: hw_free\n");
128 snd_pcm_lib_free_pages(substream);
129
130 return 0;
131}
132
133static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
134{
135 struct snd_soc_pcm_runtime *rtd = substream->private_data;
136 struct sst_byt_priv_data *pdata =
137 snd_soc_platform_get_drvdata(rtd->platform);
138 struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
139 struct sst_byt *byt = pdata->byt;
140
141 dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd);
142
143 switch (cmd) {
144 case SNDRV_PCM_TRIGGER_START:
145 sst_byt_stream_start(byt, pcm_data->stream);
146 break;
147 case SNDRV_PCM_TRIGGER_RESUME:
148 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
149 sst_byt_stream_resume(byt, pcm_data->stream);
150 break;
151 case SNDRV_PCM_TRIGGER_STOP:
152 sst_byt_stream_stop(byt, pcm_data->stream);
153 break;
154 case SNDRV_PCM_TRIGGER_SUSPEND:
155 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
156 sst_byt_stream_pause(byt, pcm_data->stream);
157 break;
158 default:
159 break;
160 }
161
162 return 0;
163}
164
165static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data)
166{
167 struct sst_byt_pcm_data *pcm_data = data;
168 struct snd_pcm_substream *substream = pcm_data->substream;
169 struct snd_pcm_runtime *runtime = substream->runtime;
170 struct snd_soc_pcm_runtime *rtd = substream->private_data;
171 u32 pos;
172
173 pos = frames_to_bytes(runtime,
174 (runtime->control->appl_ptr %
175 runtime->buffer_size));
176
177 dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
178
179 snd_pcm_period_elapsed(substream);
180 return pos;
181}
182
183static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream)
184{
185 struct snd_soc_pcm_runtime *rtd = substream->private_data;
186 struct snd_pcm_runtime *runtime = substream->runtime;
187 struct sst_byt_priv_data *pdata =
188 snd_soc_platform_get_drvdata(rtd->platform);
189 struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
190 struct sst_byt *byt = pdata->byt;
191 snd_pcm_uframes_t offset;
192 int pos;
193
194 pos = sst_byt_get_dsp_position(byt, pcm_data->stream,
195 snd_pcm_lib_buffer_bytes(substream));
196 offset = bytes_to_frames(runtime, pos);
197
198 dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n",
199 frames_to_bytes(runtime, (u32)offset));
200 return offset;
201}
202
203static int sst_byt_pcm_open(struct snd_pcm_substream *substream)
204{
205 struct snd_soc_pcm_runtime *rtd = substream->private_data;
206 struct sst_byt_priv_data *pdata =
207 snd_soc_platform_get_drvdata(rtd->platform);
208 struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
209 struct sst_byt *byt = pdata->byt;
210
211 dev_dbg(rtd->dev, "PCM: open\n");
212
213 pcm_data = &pdata->pcm[rtd->cpu_dai->id];
214 mutex_lock(&pcm_data->mutex);
215
216 snd_soc_pcm_set_drvdata(rtd, pcm_data);
217 pcm_data->substream = substream;
218
219 snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware);
220
221 pcm_data->stream = sst_byt_stream_new(byt, rtd->cpu_dai->id + 1,
222 byt_notify_pointer, pcm_data);
223 if (pcm_data->stream == NULL) {
224 dev_err(rtd->dev, "failed to create stream\n");
225 mutex_unlock(&pcm_data->mutex);
226 return -EINVAL;
227 }
228
229 mutex_unlock(&pcm_data->mutex);
230 return 0;
231}
232
233static int sst_byt_pcm_close(struct snd_pcm_substream *substream)
234{
235 struct snd_soc_pcm_runtime *rtd = substream->private_data;
236 struct sst_byt_priv_data *pdata =
237 snd_soc_platform_get_drvdata(rtd->platform);
238 struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
239 struct sst_byt *byt = pdata->byt;
240 int ret;
241
242 dev_dbg(rtd->dev, "PCM: close\n");
243
244 mutex_lock(&pcm_data->mutex);
245 ret = sst_byt_stream_free(byt, pcm_data->stream);
246 if (ret < 0) {
247 dev_dbg(rtd->dev, "Free stream fail\n");
248 goto out;
249 }
250 pcm_data->stream = NULL;
251
252out:
253 mutex_unlock(&pcm_data->mutex);
254 return ret;
255}
256
257static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream,
258 struct vm_area_struct *vma)
259{
260 struct snd_soc_pcm_runtime *rtd = substream->private_data;
261
262 dev_dbg(rtd->dev, "PCM: mmap\n");
263 return snd_pcm_lib_default_mmap(substream, vma);
264}
265
266static struct snd_pcm_ops sst_byt_pcm_ops = {
267 .open = sst_byt_pcm_open,
268 .close = sst_byt_pcm_close,
269 .ioctl = snd_pcm_lib_ioctl,
270 .hw_params = sst_byt_pcm_hw_params,
271 .hw_free = sst_byt_pcm_hw_free,
272 .trigger = sst_byt_pcm_trigger,
273 .pointer = sst_byt_pcm_pointer,
274 .mmap = sst_byt_pcm_mmap,
275};
276
277static void sst_byt_pcm_free(struct snd_pcm *pcm)
278{
279 snd_pcm_lib_preallocate_free_for_all(pcm);
280}
281
282static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
283{
284 struct snd_pcm *pcm = rtd->pcm;
285 size_t size;
286 int ret = 0;
287
288 ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32));
289 if (ret)
290 return ret;
291
292 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
293 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
294 size = sst_byt_pcm_hardware.buffer_bytes_max;
295 ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
296 SNDRV_DMA_TYPE_DEV,
297 rtd->card->dev,
298 size, size);
299 if (ret) {
300 dev_err(rtd->dev, "dma buffer allocation failed %d\n",
301 ret);
302 return ret;
303 }
304 }
305
306 return ret;
307}
308
309static struct snd_soc_dai_driver byt_dais[] = {
310 {
311 .name = "Front-cpu-dai",
312 .playback = {
313 .stream_name = "System Playback",
314 .channels_min = 2,
315 .channels_max = 2,
316 .rates = SNDRV_PCM_RATE_48000,
317 .formats = SNDRV_PCM_FMTBIT_S24_3LE |
318 SNDRV_PCM_FMTBIT_S16_LE,
319 },
320 },
321 {
322 .name = "Mic1-cpu-dai",
323 .capture = {
324 .stream_name = "Analog Capture",
325 .channels_min = 2,
326 .channels_max = 2,
327 .rates = SNDRV_PCM_RATE_48000,
328 .formats = SNDRV_PCM_FMTBIT_S16_LE,
329 },
330 },
331};
332
333static int sst_byt_pcm_probe(struct snd_soc_platform *platform)
334{
335 struct sst_pdata *plat_data = dev_get_platdata(platform->dev);
336 struct sst_byt_priv_data *priv_data;
337 int i;
338
339 if (!plat_data)
340 return -ENODEV;
341
342 priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data),
343 GFP_KERNEL);
344 priv_data->byt = plat_data->dsp;
345 snd_soc_platform_set_drvdata(platform, priv_data);
346
347 for (i = 0; i < ARRAY_SIZE(byt_dais); i++)
348 mutex_init(&priv_data->pcm[i].mutex);
349
350 return 0;
351}
352
353static int sst_byt_pcm_remove(struct snd_soc_platform *platform)
354{
355 return 0;
356}
357
358static struct snd_soc_platform_driver byt_soc_platform = {
359 .probe = sst_byt_pcm_probe,
360 .remove = sst_byt_pcm_remove,
361 .ops = &sst_byt_pcm_ops,
362 .pcm_new = sst_byt_pcm_new,
363 .pcm_free = sst_byt_pcm_free,
364};
365
366static const struct snd_soc_component_driver byt_dai_component = {
367 .name = "byt-dai",
368};
369
370static int sst_byt_pcm_dev_probe(struct platform_device *pdev)
371{
372 struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
373 int ret;
374
375 ret = sst_byt_dsp_init(&pdev->dev, sst_pdata);
376 if (ret < 0)
377 return -ENODEV;
378
379 ret = snd_soc_register_platform(&pdev->dev, &byt_soc_platform);
380 if (ret < 0)
381 goto err_plat;
382
383 ret = snd_soc_register_component(&pdev->dev, &byt_dai_component,
384 byt_dais, ARRAY_SIZE(byt_dais));
385 if (ret < 0)
386 goto err_comp;
387
388 return 0;
389
390err_comp:
391 snd_soc_unregister_platform(&pdev->dev);
392err_plat:
393 sst_byt_dsp_free(&pdev->dev, sst_pdata);
394 return ret;
395}
396
397static int sst_byt_pcm_dev_remove(struct platform_device *pdev)
398{
399 struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
400
401 snd_soc_unregister_platform(&pdev->dev);
402 snd_soc_unregister_component(&pdev->dev);
403 sst_byt_dsp_free(&pdev->dev, sst_pdata);
404
405 return 0;
406}
407
408static struct platform_driver sst_byt_pcm_driver = {
409 .driver = {
410 .name = "baytrail-pcm-audio",
411 .owner = THIS_MODULE,
412 },
413
414 .probe = sst_byt_pcm_dev_probe,
415 .remove = sst_byt_pcm_dev_remove,
416};
417module_platform_driver(sst_byt_pcm_driver);
418
419MODULE_AUTHOR("Jarkko Nikula");
420MODULE_DESCRIPTION("Baytrail PCM");
421MODULE_LICENSE("GPL v2");
422MODULE_ALIAS("platform:baytrail-pcm-audio");
diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h
new file mode 100644
index 000000000000..fe8e81aad646
--- /dev/null
+++ b/sound/soc/intel/sst-dsp-priv.h
@@ -0,0 +1,309 @@
1/*
2 * Intel Smart Sound Technology
3 *
4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#ifndef __SOUND_SOC_SST_DSP_PRIV_H
18#define __SOUND_SOC_SST_DSP_PRIV_H
19
20#include <linux/kernel.h>
21#include <linux/types.h>
22#include <linux/interrupt.h>
23#include <linux/firmware.h>
24
25struct sst_mem_block;
26struct sst_module;
27struct sst_fw;
28
29/*
30 * DSP Operations exported by platform Audio DSP driver.
31 */
32struct sst_ops {
33 /* DSP core boot / reset */
34 void (*boot)(struct sst_dsp *);
35 void (*reset)(struct sst_dsp *);
36
37 /* Shim IO */
38 void (*write)(void __iomem *addr, u32 offset, u32 value);
39 u32 (*read)(void __iomem *addr, u32 offset);
40 void (*write64)(void __iomem *addr, u32 offset, u64 value);
41 u64 (*read64)(void __iomem *addr, u32 offset);
42
43 /* DSP I/DRAM IO */
44 void (*ram_read)(struct sst_dsp *sst, void *dest, void __iomem *src,
45 size_t bytes);
46 void (*ram_write)(struct sst_dsp *sst, void __iomem *dest, void *src,
47 size_t bytes);
48
49 void (*dump)(struct sst_dsp *);
50
51 /* IRQ handlers */
52 irqreturn_t (*irq_handler)(int irq, void *context);
53
54 /* SST init and free */
55 int (*init)(struct sst_dsp *sst, struct sst_pdata *pdata);
56 void (*free)(struct sst_dsp *sst);
57
58 /* FW module parser/loader */
59 int (*parse_fw)(struct sst_fw *sst_fw);
60};
61
62/*
63 * Audio DSP memory offsets and addresses.
64 */
65struct sst_addr {
66 u32 lpe_base;
67 u32 shim_offset;
68 u32 iram_offset;
69 u32 dram_offset;
70 void __iomem *lpe;
71 void __iomem *shim;
72 void __iomem *pci_cfg;
73 void __iomem *fw_ext;
74};
75
76/*
77 * Audio DSP Mailbox configuration.
78 */
79struct sst_mailbox {
80 void __iomem *in_base;
81 void __iomem *out_base;
82 size_t in_size;
83 size_t out_size;
84};
85
86/*
87 * Audio DSP Firmware data types.
88 */
89enum sst_data_type {
90 SST_DATA_M = 0, /* module block data */
91 SST_DATA_P = 1, /* peristant data (text, data) */
92 SST_DATA_S = 2, /* scratch data (usually buffers) */
93};
94
95/*
96 * Audio DSP memory block types.
97 */
98enum sst_mem_type {
99 SST_MEM_IRAM = 0,
100 SST_MEM_DRAM = 1,
101 SST_MEM_ANY = 2,
102 SST_MEM_CACHE= 3,
103};
104
105/*
106 * Audio DSP Generic Firmware File.
107 *
108 * SST Firmware files can consist of 1..N modules. This generic structure is
109 * used to manage each firmware file and it's modules regardless of SST firmware
110 * type. A SST driver may load multiple FW files.
111 */
112struct sst_fw {
113 struct sst_dsp *dsp;
114
115 /* base addresses of FW file data */
116 dma_addr_t dmable_fw_paddr; /* physical address of fw data */
117 void *dma_buf; /* virtual address of fw data */
118 u32 size; /* size of fw data */
119
120 /* lists */
121 struct list_head list; /* DSP list of FW */
122 struct list_head module_list; /* FW list of modules */
123
124 void *private; /* core doesn't touch this */
125};
126
127/*
128 * Audio DSP Generic Module data.
129 *
130 * This is used to dsecribe any sections of persistent (text and data) and
131 * scratch (buffers) of module data in ADSP memory space.
132 */
133struct sst_module_data {
134
135 enum sst_mem_type type; /* destination memory type */
136 enum sst_data_type data_type; /* type of module data */
137
138 u32 size; /* size in bytes */
139 u32 offset; /* offset in FW file */
140 u32 data_offset; /* offset in ADSP memory space */
141 void *data; /* module data */
142};
143
144/*
145 * Audio DSP Generic Module Template.
146 *
147 * Used to define and register a new FW module. This data is extracted from
148 * FW module header information.
149 */
150struct sst_module_template {
151 u32 id;
152 u32 entry; /* entry point */
153 struct sst_module_data s; /* scratch data */
154 struct sst_module_data p; /* peristant data */
155};
156
157/*
158 * Audio DSP Generic Module.
159 *
160 * Each Firmware file can consist of 1..N modules. A module can span multiple
161 * ADSP memory blocks. The simplest FW will be a file with 1 module.
162 */
163struct sst_module {
164 struct sst_dsp *dsp;
165 struct sst_fw *sst_fw; /* parent FW we belong too */
166
167 /* module configuration */
168 u32 id;
169 u32 entry; /* module entry point */
170 u32 offset; /* module offset in firmware file */
171 u32 size; /* module size */
172 struct sst_module_data s; /* scratch data */
173 struct sst_module_data p; /* peristant data */
174
175 /* runtime */
176 u32 usage_count; /* can be unloaded if count == 0 */
177 void *private; /* core doesn't touch this */
178
179 /* lists */
180 struct list_head block_list; /* Module list of blocks in use */
181 struct list_head list; /* DSP list of modules */
182 struct list_head list_fw; /* FW list of modules */
183};
184
185/*
186 * SST Memory Block operations.
187 */
188struct sst_block_ops {
189 int (*enable)(struct sst_mem_block *block);
190 int (*disable)(struct sst_mem_block *block);
191};
192
193/*
194 * SST Generic Memory Block.
195 *
196 * SST ADP memory has multiple IRAM and DRAM blocks. Some ADSP blocks can be
197 * power gated.
198 */
199struct sst_mem_block {
200 struct sst_dsp *dsp;
201 struct sst_module *module; /* module that uses this block */
202
203 /* block config */
204 u32 offset; /* offset from base */
205 u32 size; /* block size */
206 u32 index; /* block index 0..N */
207 enum sst_mem_type type; /* block memory type IRAM/DRAM */
208 struct sst_block_ops *ops; /* block operations, if any */
209
210 /* block status */
211 enum sst_data_type data_type; /* data type held in this block */
212 u32 bytes_used; /* bytes in use by modules */
213 void *private; /* generic core does not touch this */
214 int users; /* number of modules using this block */
215
216 /* block lists */
217 struct list_head module_list; /* Module list of blocks */
218 struct list_head list; /* Map list of free/used blocks */
219};
220
221/*
222 * Generic SST Shim Interface.
223 */
224struct sst_dsp {
225
226 /* runtime */
227 struct sst_dsp_device *sst_dev;
228 spinlock_t spinlock; /* IPC locking */
229 struct mutex mutex; /* DSP FW lock */
230 struct device *dev;
231 void *thread_context;
232 int irq;
233 u32 id;
234
235 /* list of free and used ADSP memory blocks */
236 struct list_head used_block_list;
237 struct list_head free_block_list;
238
239 /* operations */
240 struct sst_ops *ops;
241
242 /* debug FS */
243 struct dentry *debugfs_root;
244
245 /* base addresses */
246 struct sst_addr addr;
247
248 /* mailbox */
249 struct sst_mailbox mailbox;
250
251 /* SST FW files loaded and their modules */
252 struct list_head module_list;
253 struct list_head fw_list;
254
255 /* platform data */
256 struct sst_pdata *pdata;
257
258 /* DMA FW loading */
259 struct sst_dma *dma;
260 bool fw_use_dma;
261};
262
263/* Size optimised DRAM/IRAM memcpy */
264static inline void sst_dsp_write(struct sst_dsp *sst, void *src,
265 u32 dest_offset, size_t bytes)
266{
267 sst->ops->ram_write(sst, sst->addr.lpe + dest_offset, src, bytes);
268}
269
270static inline void sst_dsp_read(struct sst_dsp *sst, void *dest,
271 u32 src_offset, size_t bytes)
272{
273 sst->ops->ram_read(sst, dest, sst->addr.lpe + src_offset, bytes);
274}
275
276static inline void *sst_dsp_get_thread_context(struct sst_dsp *sst)
277{
278 return sst->thread_context;
279}
280
281/* Create/Free FW files - can contain multiple modules */
282struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
283 const struct firmware *fw, void *private);
284void sst_fw_free(struct sst_fw *sst_fw);
285void sst_fw_free_all(struct sst_dsp *dsp);
286
287/* Create/Free firmware modules */
288struct sst_module *sst_module_new(struct sst_fw *sst_fw,
289 struct sst_module_template *template, void *private);
290void sst_module_free(struct sst_module *sst_module);
291int sst_module_insert(struct sst_module *sst_module);
292int sst_module_remove(struct sst_module *sst_module);
293int sst_module_insert_fixed_block(struct sst_module *module,
294 struct sst_module_data *data);
295struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id);
296
297/* allocate/free pesistent/scratch memory regions managed by drv */
298struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp);
299void sst_mem_block_free_scratch(struct sst_dsp *dsp,
300 struct sst_module *scratch);
301int sst_block_module_remove(struct sst_module *module);
302
303/* Register the DSPs memory blocks - would be nice to read from ACPI */
304struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
305 u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
306 void *private);
307void sst_mem_block_unregister_all(struct sst_dsp *dsp);
308
309#endif
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c
new file mode 100644
index 000000000000..0c129fd85ecf
--- /dev/null
+++ b/sound/soc/intel/sst-dsp.c
@@ -0,0 +1,385 @@
1/*
2 * Intel Smart Sound Technology (SST) DSP Core Driver
3 *
4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/slab.h>
18#include <linux/export.h>
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/platform_device.h>
22#include <linux/io.h>
23
24#include "sst-dsp.h"
25#include "sst-dsp-priv.h"
26
27#define CREATE_TRACE_POINTS
28#include <trace/events/intel-sst.h>
29
30/* Internal generic low-level SST IO functions - can be overidden */
31void sst_shim32_write(void __iomem *addr, u32 offset, u32 value)
32{
33 writel(value, addr + offset);
34}
35EXPORT_SYMBOL_GPL(sst_shim32_write);
36
37u32 sst_shim32_read(void __iomem *addr, u32 offset)
38{
39 return readl(addr + offset);
40}
41EXPORT_SYMBOL_GPL(sst_shim32_read);
42
43void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value)
44{
45 memcpy_toio(addr + offset, &value, sizeof(value));
46}
47EXPORT_SYMBOL_GPL(sst_shim32_write64);
48
49u64 sst_shim32_read64(void __iomem *addr, u32 offset)
50{
51 u64 val;
52
53 memcpy_fromio(&val, addr + offset, sizeof(val));
54 return val;
55}
56EXPORT_SYMBOL_GPL(sst_shim32_read64);
57
58static inline void _sst_memcpy_toio_32(volatile u32 __iomem *dest,
59 u32 *src, size_t bytes)
60{
61 int i, words = bytes >> 2;
62
63 for (i = 0; i < words; i++)
64 writel(src[i], dest + i);
65}
66
67static inline void _sst_memcpy_fromio_32(u32 *dest,
68 const volatile __iomem u32 *src, size_t bytes)
69{
70 int i, words = bytes >> 2;
71
72 for (i = 0; i < words; i++)
73 dest[i] = readl(src + i);
74}
75
76void sst_memcpy_toio_32(struct sst_dsp *sst,
77 void __iomem *dest, void *src, size_t bytes)
78{
79 _sst_memcpy_toio_32(dest, src, bytes);
80}
81EXPORT_SYMBOL_GPL(sst_memcpy_toio_32);
82
83void sst_memcpy_fromio_32(struct sst_dsp *sst, void *dest,
84 void __iomem *src, size_t bytes)
85{
86 _sst_memcpy_fromio_32(dest, src, bytes);
87}
88EXPORT_SYMBOL_GPL(sst_memcpy_fromio_32);
89
90/* Public API */
91void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value)
92{
93 unsigned long flags;
94
95 spin_lock_irqsave(&sst->spinlock, flags);
96 sst->ops->write(sst->addr.shim, offset, value);
97 spin_unlock_irqrestore(&sst->spinlock, flags);
98}
99EXPORT_SYMBOL_GPL(sst_dsp_shim_write);
100
101u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset)
102{
103 unsigned long flags;
104 u32 val;
105
106 spin_lock_irqsave(&sst->spinlock, flags);
107 val = sst->ops->read(sst->addr.shim, offset);
108 spin_unlock_irqrestore(&sst->spinlock, flags);
109
110 return val;
111}
112EXPORT_SYMBOL_GPL(sst_dsp_shim_read);
113
114void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value)
115{
116 unsigned long flags;
117
118 spin_lock_irqsave(&sst->spinlock, flags);
119 sst->ops->write64(sst->addr.shim, offset, value);
120 spin_unlock_irqrestore(&sst->spinlock, flags);
121}
122EXPORT_SYMBOL_GPL(sst_dsp_shim_write64);
123
124u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset)
125{
126 unsigned long flags;
127 u64 val;
128
129 spin_lock_irqsave(&sst->spinlock, flags);
130 val = sst->ops->read64(sst->addr.shim, offset);
131 spin_unlock_irqrestore(&sst->spinlock, flags);
132
133 return val;
134}
135EXPORT_SYMBOL_GPL(sst_dsp_shim_read64);
136
137void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value)
138{
139 sst->ops->write(sst->addr.shim, offset, value);
140}
141EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked);
142
143u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset)
144{
145 return sst->ops->read(sst->addr.shim, offset);
146}
147EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked);
148
149void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value)
150{
151 sst->ops->write64(sst->addr.shim, offset, value);
152}
153EXPORT_SYMBOL_GPL(sst_dsp_shim_write64_unlocked);
154
155u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset)
156{
157 return sst->ops->read64(sst->addr.shim, offset);
158}
159EXPORT_SYMBOL_GPL(sst_dsp_shim_read64_unlocked);
160
161int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
162 u32 mask, u32 value)
163{
164 bool change;
165 unsigned int old, new;
166 u32 ret;
167
168 ret = sst_dsp_shim_read_unlocked(sst, offset);
169
170 old = ret;
171 new = (old & (~mask)) | (value & mask);
172
173 change = (old != new);
174 if (change)
175 sst_dsp_shim_write_unlocked(sst, offset, new);
176
177 return change;
178}
179EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked);
180
181int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
182 u64 mask, u64 value)
183{
184 bool change;
185 u64 old, new;
186
187 old = sst_dsp_shim_read64_unlocked(sst, offset);
188
189 new = (old & (~mask)) | (value & mask);
190
191 change = (old != new);
192 if (change)
193 sst_dsp_shim_write64_unlocked(sst, offset, new);
194
195 return change;
196}
197EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked);
198
199int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
200 u32 mask, u32 value)
201{
202 unsigned long flags;
203 bool change;
204
205 spin_lock_irqsave(&sst->spinlock, flags);
206 change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value);
207 spin_unlock_irqrestore(&sst->spinlock, flags);
208 return change;
209}
210EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits);
211
212int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
213 u64 mask, u64 value)
214{
215 unsigned long flags;
216 bool change;
217
218 spin_lock_irqsave(&sst->spinlock, flags);
219 change = sst_dsp_shim_update_bits64_unlocked(sst, offset, mask, value);
220 spin_unlock_irqrestore(&sst->spinlock, flags);
221 return change;
222}
223EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64);
224
225void sst_dsp_dump(struct sst_dsp *sst)
226{
227 sst->ops->dump(sst);
228}
229EXPORT_SYMBOL_GPL(sst_dsp_dump);
230
231void sst_dsp_reset(struct sst_dsp *sst)
232{
233 sst->ops->reset(sst);
234}
235EXPORT_SYMBOL_GPL(sst_dsp_reset);
236
237int sst_dsp_boot(struct sst_dsp *sst)
238{
239 sst->ops->boot(sst);
240 return 0;
241}
242EXPORT_SYMBOL_GPL(sst_dsp_boot);
243
244void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg)
245{
246 sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY);
247 trace_sst_ipc_msg_tx(msg);
248}
249EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_tx);
250
251u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp)
252{
253 u32 msg;
254
255 msg = sst_dsp_shim_read_unlocked(dsp, SST_IPCX);
256 trace_sst_ipc_msg_rx(msg);
257
258 return msg;
259}
260EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_rx);
261
262int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size,
263 u32 outbox_offset, size_t outbox_size)
264{
265 sst->mailbox.in_base = sst->addr.lpe + inbox_offset;
266 sst->mailbox.out_base = sst->addr.lpe + outbox_offset;
267 sst->mailbox.in_size = inbox_size;
268 sst->mailbox.out_size = outbox_size;
269 return 0;
270}
271EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init);
272
273void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes)
274{
275 u32 i;
276
277 trace_sst_ipc_outbox_write(bytes);
278
279 memcpy_toio(sst->mailbox.out_base, message, bytes);
280
281 for (i = 0; i < bytes; i += 4)
282 trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i));
283}
284EXPORT_SYMBOL_GPL(sst_dsp_outbox_write);
285
286void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes)
287{
288 u32 i;
289
290 trace_sst_ipc_outbox_read(bytes);
291
292 memcpy_fromio(message, sst->mailbox.out_base, bytes);
293
294 for (i = 0; i < bytes; i += 4)
295 trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i));
296}
297EXPORT_SYMBOL_GPL(sst_dsp_outbox_read);
298
299void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes)
300{
301 u32 i;
302
303 trace_sst_ipc_inbox_write(bytes);
304
305 memcpy_toio(sst->mailbox.in_base, message, bytes);
306
307 for (i = 0; i < bytes; i += 4)
308 trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i));
309}
310EXPORT_SYMBOL_GPL(sst_dsp_inbox_write);
311
312void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes)
313{
314 u32 i;
315
316 trace_sst_ipc_inbox_read(bytes);
317
318 memcpy_fromio(message, sst->mailbox.in_base, bytes);
319
320 for (i = 0; i < bytes; i += 4)
321 trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i));
322}
323EXPORT_SYMBOL_GPL(sst_dsp_inbox_read);
324
325struct sst_dsp *sst_dsp_new(struct device *dev,
326 struct sst_dsp_device *sst_dev, struct sst_pdata *pdata)
327{
328 struct sst_dsp *sst;
329 int err;
330
331 dev_dbg(dev, "initialising audio DSP id 0x%x\n", pdata->id);
332
333 sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL);
334 if (sst == NULL)
335 return NULL;
336
337 spin_lock_init(&sst->spinlock);
338 mutex_init(&sst->mutex);
339 sst->dev = dev;
340 sst->thread_context = sst_dev->thread_context;
341 sst->sst_dev = sst_dev;
342 sst->id = pdata->id;
343 sst->irq = pdata->irq;
344 sst->ops = sst_dev->ops;
345 sst->pdata = pdata;
346 INIT_LIST_HEAD(&sst->used_block_list);
347 INIT_LIST_HEAD(&sst->free_block_list);
348 INIT_LIST_HEAD(&sst->module_list);
349 INIT_LIST_HEAD(&sst->fw_list);
350
351 /* Initialise SST Audio DSP */
352 if (sst->ops->init) {
353 err = sst->ops->init(sst, pdata);
354 if (err < 0)
355 return NULL;
356 }
357
358 /* Register the ISR */
359 err = request_threaded_irq(sst->irq, sst->ops->irq_handler,
360 sst_dev->thread, IRQF_SHARED, "AudioDSP", sst);
361 if (err)
362 goto irq_err;
363
364 return sst;
365
366irq_err:
367 if (sst->ops->free)
368 sst->ops->free(sst);
369
370 return NULL;
371}
372EXPORT_SYMBOL_GPL(sst_dsp_new);
373
374void sst_dsp_free(struct sst_dsp *sst)
375{
376 free_irq(sst->irq, sst);
377 if (sst->ops->free)
378 sst->ops->free(sst);
379}
380EXPORT_SYMBOL_GPL(sst_dsp_free);
381
382/* Module information */
383MODULE_AUTHOR("Liam Girdwood");
384MODULE_DESCRIPTION("Intel SST Core");
385MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h
new file mode 100644
index 000000000000..74052b59485c
--- /dev/null
+++ b/sound/soc/intel/sst-dsp.h
@@ -0,0 +1,233 @@
1/*
2 * Intel Smart Sound Technology (SST) Core
3 *
4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#ifndef __SOUND_SOC_SST_DSP_H
18#define __SOUND_SOC_SST_DSP_H
19
20#include <linux/kernel.h>
21#include <linux/types.h>
22#include <linux/interrupt.h>
23
24/* SST Device IDs */
25#define SST_DEV_ID_LYNX_POINT 0x33C8
26#define SST_DEV_ID_WILDCAT_POINT 0x3438
27#define SST_DEV_ID_BYT 0x0F28
28
29/* Supported SST DMA Devices */
30#define SST_DMA_TYPE_DW 1
31#define SST_DMA_TYPE_MID 2
32
33/* SST Shim register map
34 * The register naming can differ between products. Some products also
35 * contain extra functionality.
36 */
37#define SST_CSR 0x00
38#define SST_PISR 0x08
39#define SST_PIMR 0x10
40#define SST_ISRX 0x18
41#define SST_ISRD 0x20
42#define SST_IMRX 0x28
43#define SST_IMRD 0x30
44#define SST_IPCX 0x38 /* IPC IA -> SST */
45#define SST_IPCD 0x40 /* IPC SST -> IA */
46#define SST_ISRSC 0x48
47#define SST_ISRLPESC 0x50
48#define SST_IMRSC 0x58
49#define SST_IMRLPESC 0x60
50#define SST_IPCSC 0x68
51#define SST_IPCLPESC 0x70
52#define SST_CLKCTL 0x78
53#define SST_CSR2 0x80
54#define SST_LTRC 0xE0
55#define SST_HDMC 0xE8
56#define SST_DBGO 0xF0
57
58#define SST_SHIM_SIZE 0x100
59#define SST_PWMCTRL 0x1000
60
61/* SST Shim Register bits
62 * The register bit naming can differ between products. Some products also
63 * contain extra functionality.
64 */
65
66/* CSR / CS */
67#define SST_CSR_RST (0x1 << 1)
68#define SST_CSR_SBCS0 (0x1 << 2)
69#define SST_CSR_SBCS1 (0x1 << 3)
70#define SST_CSR_DCS(x) (x << 4)
71#define SST_CSR_DCS_MASK (0x7 << 4)
72#define SST_CSR_STALL (0x1 << 10)
73#define SST_CSR_S0IOCS (0x1 << 21)
74#define SST_CSR_S1IOCS (0x1 << 23)
75#define SST_CSR_LPCS (0x1 << 31)
76#define SST_BYT_CSR_RST (0x1 << 0)
77#define SST_BYT_CSR_VECTOR_SEL (0x1 << 1)
78#define SST_BYT_CSR_STALL (0x1 << 2)
79#define SST_BYT_CSR_PWAITMODE (0x1 << 3)
80
81/* ISRX / ISC */
82#define SST_ISRX_BUSY (0x1 << 1)
83#define SST_ISRX_DONE (0x1 << 0)
84#define SST_BYT_ISRX_REQUEST (0x1 << 1)
85
86/* ISRD / ISD */
87#define SST_ISRD_BUSY (0x1 << 1)
88#define SST_ISRD_DONE (0x1 << 0)
89
90/* IMRX / IMC */
91#define SST_IMRX_BUSY (0x1 << 1)
92#define SST_IMRX_DONE (0x1 << 0)
93#define SST_BYT_IMRX_REQUEST (0x1 << 1)
94
95/* IPCX / IPCC */
96#define SST_IPCX_DONE (0x1 << 30)
97#define SST_IPCX_BUSY (0x1 << 31)
98#define SST_BYT_IPCX_DONE ((u64)0x1 << 62)
99#define SST_BYT_IPCX_BUSY ((u64)0x1 << 63)
100
101/* IPCD */
102#define SST_IPCD_DONE (0x1 << 30)
103#define SST_IPCD_BUSY (0x1 << 31)
104#define SST_BYT_IPCD_DONE ((u64)0x1 << 62)
105#define SST_BYT_IPCD_BUSY ((u64)0x1 << 63)
106
107/* CLKCTL */
108#define SST_CLKCTL_SMOS(x) (x << 24)
109#define SST_CLKCTL_MASK (3 << 24)
110#define SST_CLKCTL_DCPLCG (1 << 18)
111#define SST_CLKCTL_SCOE1 (1 << 17)
112#define SST_CLKCTL_SCOE0 (1 << 16)
113
114/* CSR2 / CS2 */
115#define SST_CSR2_SDFD_SSP0 (1 << 1)
116#define SST_CSR2_SDFD_SSP1 (1 << 2)
117
118/* LTRC */
119#define SST_LTRC_VAL(x) (x << 0)
120
121/* HDMC */
122#define SST_HDMC_HDDA0(x) (x << 0)
123#define SST_HDMC_HDDA1(x) (x << 7)
124
125
126/* SST Vendor Defined Registers and bits */
127#define SST_VDRTCTL0 0xa0
128#define SST_VDRTCTL1 0xa4
129#define SST_VDRTCTL2 0xa8
130#define SST_VDRTCTL3 0xaC
131
132/* VDRTCTL0 */
133#define SST_VDRTCL0_DSRAMPGE_SHIFT 16
134#define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT)
135#define SST_VDRTCL0_ISRAMPGE_SHIFT 6
136#define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT)
137
138struct sst_dsp;
139
140/*
141 * SST Device.
142 *
143 * This structure is populated by the SST core driver.
144 */
145struct sst_dsp_device {
146 /* Mandatory fields */
147 struct sst_ops *ops;
148 irqreturn_t (*thread)(int irq, void *context);
149 void *thread_context;
150};
151
152/*
153 * SST Platform Data.
154 */
155struct sst_pdata {
156 /* ACPI data */
157 u32 lpe_base;
158 u32 lpe_size;
159 u32 pcicfg_base;
160 u32 pcicfg_size;
161 u32 fw_base;
162 u32 fw_size;
163 int irq;
164
165 /* Firmware */
166 const struct firmware *fw;
167
168 /* DMA */
169 u32 dma_base;
170 u32 dma_size;
171 int dma_engine;
172
173 /* DSP */
174 u32 id;
175 void *dsp;
176};
177
178/* Initialization */
179struct sst_dsp *sst_dsp_new(struct device *dev,
180 struct sst_dsp_device *sst_dev, struct sst_pdata *pdata);
181void sst_dsp_free(struct sst_dsp *sst);
182
183/* SHIM Read / Write */
184void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value);
185u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset);
186int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset,
187 u32 mask, u32 value);
188void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value);
189u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset);
190int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset,
191 u64 mask, u64 value);
192
193/* SHIM Read / Write Unlocked for callers already holding sst lock */
194void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value);
195u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset);
196int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset,
197 u32 mask, u32 value);
198void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value);
199u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset);
200int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset,
201 u64 mask, u64 value);
202
203/* Internal generic low-level SST IO functions - can be overidden */
204void sst_shim32_write(void __iomem *addr, u32 offset, u32 value);
205u32 sst_shim32_read(void __iomem *addr, u32 offset);
206void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value);
207u64 sst_shim32_read64(void __iomem *addr, u32 offset);
208void sst_memcpy_toio_32(struct sst_dsp *sst,
209 void __iomem *dest, void *src, size_t bytes);
210void sst_memcpy_fromio_32(struct sst_dsp *sst,
211 void *dest, void __iomem *src, size_t bytes);
212
213/* DSP reset & boot */
214void sst_dsp_reset(struct sst_dsp *sst);
215int sst_dsp_boot(struct sst_dsp *sst);
216
217/* Msg IO */
218void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg);
219u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp);
220
221/* Mailbox management */
222int sst_dsp_mailbox_init(struct sst_dsp *dsp, u32 inbox_offset,
223 size_t inbox_size, u32 outbox_offset, size_t outbox_size);
224void sst_dsp_inbox_write(struct sst_dsp *dsp, void *message, size_t bytes);
225void sst_dsp_inbox_read(struct sst_dsp *dsp, void *message, size_t bytes);
226void sst_dsp_outbox_write(struct sst_dsp *dsp, void *message, size_t bytes);
227void sst_dsp_outbox_read(struct sst_dsp *dsp, void *message, size_t bytes);
228void sst_dsp_mailbox_dump(struct sst_dsp *dsp, size_t bytes);
229
230/* Debug */
231void sst_dsp_dump(struct sst_dsp *sst);
232
233#endif
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c
new file mode 100644
index 000000000000..f7687107cf7f
--- /dev/null
+++ b/sound/soc/intel/sst-firmware.c
@@ -0,0 +1,587 @@
1/*
2 * Intel SST Firmware Loader
3 *
4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/kernel.h>
18#include <linux/slab.h>
19#include <linux/sched.h>
20#include <linux/firmware.h>
21#include <linux/export.h>
22#include <linux/platform_device.h>
23#include <linux/dma-mapping.h>
24#include <linux/dmaengine.h>
25#include <linux/pci.h>
26
27#include <asm/page.h>
28#include <asm/pgtable.h>
29
30#include "sst-dsp.h"
31#include "sst-dsp-priv.h"
32
33static void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes)
34{
35 u32 i;
36
37 /* copy one 32 bit word at a time as 64 bit access is not supported */
38 for (i = 0; i < bytes; i += 4)
39 memcpy_toio(dest + i, src + i, 4);
40}
41
42/* create new generic firmware object */
43struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
44 const struct firmware *fw, void *private)
45{
46 struct sst_fw *sst_fw;
47 int err;
48
49 if (!dsp->ops->parse_fw)
50 return NULL;
51
52 sst_fw = kzalloc(sizeof(*sst_fw), GFP_KERNEL);
53 if (sst_fw == NULL)
54 return NULL;
55
56 sst_fw->dsp = dsp;
57 sst_fw->private = private;
58 sst_fw->size = fw->size;
59
60 err = dma_coerce_mask_and_coherent(dsp->dev, DMA_BIT_MASK(32));
61 if (err < 0) {
62 kfree(sst_fw);
63 return NULL;
64 }
65
66 /* allocate DMA buffer to store FW data */
67 sst_fw->dma_buf = dma_alloc_coherent(dsp->dev, sst_fw->size,
68 &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL);
69 if (!sst_fw->dma_buf) {
70 dev_err(dsp->dev, "error: DMA alloc failed\n");
71 kfree(sst_fw);
72 return NULL;
73 }
74
75 /* copy FW data to DMA-able memory */
76 memcpy((void *)sst_fw->dma_buf, (void *)fw->data, fw->size);
77
78 /* call core specific FW paser to load FW data into DSP */
79 err = dsp->ops->parse_fw(sst_fw);
80 if (err < 0) {
81 dev_err(dsp->dev, "error: parse fw failed %d\n", err);
82 goto parse_err;
83 }
84
85 mutex_lock(&dsp->mutex);
86 list_add(&sst_fw->list, &dsp->fw_list);
87 mutex_unlock(&dsp->mutex);
88
89 return sst_fw;
90
91parse_err:
92 dma_free_coherent(dsp->dev, sst_fw->size,
93 sst_fw->dma_buf,
94 sst_fw->dmable_fw_paddr);
95 kfree(sst_fw);
96 return NULL;
97}
98EXPORT_SYMBOL_GPL(sst_fw_new);
99
100/* free single firmware object */
101void sst_fw_free(struct sst_fw *sst_fw)
102{
103 struct sst_dsp *dsp = sst_fw->dsp;
104
105 mutex_lock(&dsp->mutex);
106 list_del(&sst_fw->list);
107 mutex_unlock(&dsp->mutex);
108
109 dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf,
110 sst_fw->dmable_fw_paddr);
111 kfree(sst_fw);
112}
113EXPORT_SYMBOL_GPL(sst_fw_free);
114
115/* free all firmware objects */
116void sst_fw_free_all(struct sst_dsp *dsp)
117{
118 struct sst_fw *sst_fw, *t;
119
120 mutex_lock(&dsp->mutex);
121 list_for_each_entry_safe(sst_fw, t, &dsp->fw_list, list) {
122
123 list_del(&sst_fw->list);
124 dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf,
125 sst_fw->dmable_fw_paddr);
126 kfree(sst_fw);
127 }
128 mutex_unlock(&dsp->mutex);
129}
130EXPORT_SYMBOL_GPL(sst_fw_free_all);
131
132/* create a new SST generic module from FW template */
133struct sst_module *sst_module_new(struct sst_fw *sst_fw,
134 struct sst_module_template *template, void *private)
135{
136 struct sst_dsp *dsp = sst_fw->dsp;
137 struct sst_module *sst_module;
138
139 sst_module = kzalloc(sizeof(*sst_module), GFP_KERNEL);
140 if (sst_module == NULL)
141 return NULL;
142
143 sst_module->id = template->id;
144 sst_module->dsp = dsp;
145 sst_module->sst_fw = sst_fw;
146
147 memcpy(&sst_module->s, &template->s, sizeof(struct sst_module_data));
148 memcpy(&sst_module->p, &template->p, sizeof(struct sst_module_data));
149
150 INIT_LIST_HEAD(&sst_module->block_list);
151
152 mutex_lock(&dsp->mutex);
153 list_add(&sst_module->list, &dsp->module_list);
154 mutex_unlock(&dsp->mutex);
155
156 return sst_module;
157}
158EXPORT_SYMBOL_GPL(sst_module_new);
159
160/* free firmware module and remove from available list */
161void sst_module_free(struct sst_module *sst_module)
162{
163 struct sst_dsp *dsp = sst_module->dsp;
164
165 mutex_lock(&dsp->mutex);
166 list_del(&sst_module->list);
167 mutex_unlock(&dsp->mutex);
168
169 kfree(sst_module);
170}
171EXPORT_SYMBOL_GPL(sst_module_free);
172
173static struct sst_mem_block *find_block(struct sst_dsp *dsp, int type,
174 u32 offset)
175{
176 struct sst_mem_block *block;
177
178 list_for_each_entry(block, &dsp->free_block_list, list) {
179 if (block->type == type && block->offset == offset)
180 return block;
181 }
182
183 return NULL;
184}
185
186static int block_alloc_contiguous(struct sst_module *module,
187 struct sst_module_data *data, u32 offset, int size)
188{
189 struct list_head tmp = LIST_HEAD_INIT(tmp);
190 struct sst_dsp *dsp = module->dsp;
191 struct sst_mem_block *block;
192
193 while (size > 0) {
194 block = find_block(dsp, data->type, offset);
195 if (!block) {
196 list_splice(&tmp, &dsp->free_block_list);
197 return -ENOMEM;
198 }
199
200 list_move_tail(&block->list, &tmp);
201 offset += block->size;
202 size -= block->size;
203 }
204
205 list_splice(&tmp, &dsp->used_block_list);
206 return 0;
207}
208
209/* allocate free DSP blocks for module data - callers hold locks */
210static int block_alloc(struct sst_module *module,
211 struct sst_module_data *data)
212{
213 struct sst_dsp *dsp = module->dsp;
214 struct sst_mem_block *block, *tmp;
215 int ret = 0;
216
217 if (data->size == 0)
218 return 0;
219
220 /* find first free whole blocks that can hold module */
221 list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
222
223 /* ignore blocks with wrong type */
224 if (block->type != data->type)
225 continue;
226
227 if (data->size > block->size)
228 continue;
229
230 data->offset = block->offset;
231 block->data_type = data->data_type;
232 block->bytes_used = data->size % block->size;
233 list_add(&block->module_list, &module->block_list);
234 list_move(&block->list, &dsp->used_block_list);
235 dev_dbg(dsp->dev, " *module %d added block %d:%d\n",
236 module->id, block->type, block->index);
237 return 0;
238 }
239
240 /* then find free multiple blocks that can hold module */
241 list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
242
243 /* ignore blocks with wrong type */
244 if (block->type != data->type)
245 continue;
246
247 /* do we span > 1 blocks */
248 if (data->size > block->size) {
249 ret = block_alloc_contiguous(module, data,
250 block->offset + block->size,
251 data->size - block->size);
252 if (ret == 0)
253 return ret;
254 }
255 }
256
257 /* not enough free block space */
258 return -ENOMEM;
259}
260
261/* remove module from memory - callers hold locks */
262static void block_module_remove(struct sst_module *module)
263{
264 struct sst_mem_block *block, *tmp;
265 struct sst_dsp *dsp = module->dsp;
266 int err;
267
268 /* disable each block */
269 list_for_each_entry(block, &module->block_list, module_list) {
270
271 if (block->ops && block->ops->disable) {
272 err = block->ops->disable(block);
273 if (err < 0)
274 dev_err(dsp->dev,
275 "error: cant disable block %d:%d\n",
276 block->type, block->index);
277 }
278 }
279
280 /* mark each block as free */
281 list_for_each_entry_safe(block, tmp, &module->block_list, module_list) {
282 list_del(&block->module_list);
283 list_move(&block->list, &dsp->free_block_list);
284 }
285}
286
287/* prepare the memory block to receive data from host - callers hold locks */
288static int block_module_prepare(struct sst_module *module)
289{
290 struct sst_mem_block *block;
291 int ret = 0;
292
293 /* enable each block so that's it'e ready for module P/S data */
294 list_for_each_entry(block, &module->block_list, module_list) {
295
296 if (block->ops && block->ops->enable) {
297 ret = block->ops->enable(block);
298 if (ret < 0) {
299 dev_err(module->dsp->dev,
300 "error: cant disable block %d:%d\n",
301 block->type, block->index);
302 goto err;
303 }
304 }
305 }
306 return ret;
307
308err:
309 list_for_each_entry(block, &module->block_list, module_list) {
310 if (block->ops && block->ops->disable)
311 block->ops->disable(block);
312 }
313 return ret;
314}
315
316/* allocate memory blocks for static module addresses - callers hold locks */
317static int block_alloc_fixed(struct sst_module *module,
318 struct sst_module_data *data)
319{
320 struct sst_dsp *dsp = module->dsp;
321 struct sst_mem_block *block, *tmp;
322 u32 end = data->offset + data->size, block_end;
323 int err;
324
325 /* only IRAM/DRAM blocks are managed */
326 if (data->type != SST_MEM_IRAM && data->type != SST_MEM_DRAM)
327 return 0;
328
329 /* are blocks already attached to this module */
330 list_for_each_entry_safe(block, tmp, &module->block_list, module_list) {
331
332 /* force compacting mem blocks of the same data_type */
333 if (block->data_type != data->data_type)
334 continue;
335
336 block_end = block->offset + block->size;
337
338 /* find block that holds section */
339 if (data->offset >= block->offset && end < block_end)
340 return 0;
341
342 /* does block span more than 1 section */
343 if (data->offset >= block->offset && data->offset < block_end) {
344
345 err = block_alloc_contiguous(module, data,
346 block->offset + block->size,
347 data->size - block->size + data->offset - block->offset);
348 if (err < 0)
349 return -ENOMEM;
350
351 /* module already owns blocks */
352 return 0;
353 }
354 }
355
356 /* find first free blocks that can hold section in free list */
357 list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
358 block_end = block->offset + block->size;
359
360 /* find block that holds section */
361 if (data->offset >= block->offset && end < block_end) {
362
363 /* add block */
364 block->data_type = data->data_type;
365 list_move(&block->list, &dsp->used_block_list);
366 list_add(&block->module_list, &module->block_list);
367 return 0;
368 }
369
370 /* does block span more than 1 section */
371 if (data->offset >= block->offset && data->offset < block_end) {
372
373 err = block_alloc_contiguous(module, data,
374 block->offset + block->size,
375 data->size - block->size);
376 if (err < 0)
377 return -ENOMEM;
378
379 /* add block */
380 block->data_type = data->data_type;
381 list_move(&block->list, &dsp->used_block_list);
382 list_add(&block->module_list, &module->block_list);
383 return 0;
384 }
385
386 }
387
388 return -ENOMEM;
389}
390
391/* Load fixed module data into DSP memory blocks */
392int sst_module_insert_fixed_block(struct sst_module *module,
393 struct sst_module_data *data)
394{
395 struct sst_dsp *dsp = module->dsp;
396 int ret;
397
398 mutex_lock(&dsp->mutex);
399
400 /* alloc blocks that includes this section */
401 ret = block_alloc_fixed(module, data);
402 if (ret < 0) {
403 dev_err(dsp->dev,
404 "error: no free blocks for section at offset 0x%x size 0x%x\n",
405 data->offset, data->size);
406 mutex_unlock(&dsp->mutex);
407 return -ENOMEM;
408 }
409
410 /* prepare DSP blocks for module copy */
411 ret = block_module_prepare(module);
412 if (ret < 0) {
413 dev_err(dsp->dev, "error: fw module prepare failed\n");
414 goto err;
415 }
416
417 /* copy partial module data to blocks */
418 sst_memcpy32(dsp->addr.lpe + data->offset, data->data, data->size);
419
420 mutex_unlock(&dsp->mutex);
421 return ret;
422
423err:
424 block_module_remove(module);
425 mutex_unlock(&dsp->mutex);
426 return ret;
427}
428EXPORT_SYMBOL_GPL(sst_module_insert_fixed_block);
429
430/* Unload entire module from DSP memory */
431int sst_block_module_remove(struct sst_module *module)
432{
433 struct sst_dsp *dsp = module->dsp;
434
435 mutex_lock(&dsp->mutex);
436 block_module_remove(module);
437 mutex_unlock(&dsp->mutex);
438 return 0;
439}
440EXPORT_SYMBOL_GPL(sst_block_module_remove);
441
442/* register a DSP memory block for use with FW based modules */
443struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
444 u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index,
445 void *private)
446{
447 struct sst_mem_block *block;
448
449 block = kzalloc(sizeof(*block), GFP_KERNEL);
450 if (block == NULL)
451 return NULL;
452
453 block->offset = offset;
454 block->size = size;
455 block->index = index;
456 block->type = type;
457 block->dsp = dsp;
458 block->private = private;
459 block->ops = ops;
460
461 mutex_lock(&dsp->mutex);
462 list_add(&block->list, &dsp->free_block_list);
463 mutex_unlock(&dsp->mutex);
464
465 return block;
466}
467EXPORT_SYMBOL_GPL(sst_mem_block_register);
468
469/* unregister all DSP memory blocks */
470void sst_mem_block_unregister_all(struct sst_dsp *dsp)
471{
472 struct sst_mem_block *block, *tmp;
473
474 mutex_lock(&dsp->mutex);
475
476 /* unregister used blocks */
477 list_for_each_entry_safe(block, tmp, &dsp->used_block_list, list) {
478 list_del(&block->list);
479 kfree(block);
480 }
481
482 /* unregister free blocks */
483 list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
484 list_del(&block->list);
485 kfree(block);
486 }
487
488 mutex_unlock(&dsp->mutex);
489}
490EXPORT_SYMBOL_GPL(sst_mem_block_unregister_all);
491
492/* allocate scratch buffer blocks */
493struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp)
494{
495 struct sst_module *sst_module, *scratch;
496 struct sst_mem_block *block, *tmp;
497 u32 block_size;
498 int ret = 0;
499
500 scratch = kzalloc(sizeof(struct sst_module), GFP_KERNEL);
501 if (scratch == NULL)
502 return NULL;
503
504 mutex_lock(&dsp->mutex);
505
506 /* calculate required scratch size */
507 list_for_each_entry(sst_module, &dsp->module_list, list) {
508 if (scratch->s.size > sst_module->s.size)
509 scratch->s.size = scratch->s.size;
510 else
511 scratch->s.size = sst_module->s.size;
512 }
513
514 dev_dbg(dsp->dev, "scratch buffer required is %d bytes\n",
515 scratch->s.size);
516
517 /* init scratch module */
518 scratch->dsp = dsp;
519 scratch->s.type = SST_MEM_DRAM;
520 scratch->s.data_type = SST_DATA_S;
521 INIT_LIST_HEAD(&scratch->block_list);
522
523 /* check free blocks before looking at used blocks for space */
524 if (!list_empty(&dsp->free_block_list))
525 block = list_first_entry(&dsp->free_block_list,
526 struct sst_mem_block, list);
527 else
528 block = list_first_entry(&dsp->used_block_list,
529 struct sst_mem_block, list);
530 block_size = block->size;
531
532 /* allocate blocks for module scratch buffers */
533 dev_dbg(dsp->dev, "allocating scratch blocks\n");
534 ret = block_alloc(scratch, &scratch->s);
535 if (ret < 0) {
536 dev_err(dsp->dev, "error: can't alloc scratch blocks\n");
537 goto err;
538 }
539
540 /* assign the same offset of scratch to each module */
541 list_for_each_entry(sst_module, &dsp->module_list, list)
542 sst_module->s.offset = scratch->s.offset;
543
544 mutex_unlock(&dsp->mutex);
545 return scratch;
546
547err:
548 list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list)
549 list_del(&block->module_list);
550 mutex_unlock(&dsp->mutex);
551 return NULL;
552}
553EXPORT_SYMBOL_GPL(sst_mem_block_alloc_scratch);
554
555/* free all scratch blocks */
556void sst_mem_block_free_scratch(struct sst_dsp *dsp,
557 struct sst_module *scratch)
558{
559 struct sst_mem_block *block, *tmp;
560
561 mutex_lock(&dsp->mutex);
562
563 list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list)
564 list_del(&block->module_list);
565
566 mutex_unlock(&dsp->mutex);
567}
568EXPORT_SYMBOL_GPL(sst_mem_block_free_scratch);
569
570/* get a module from it's unique ID */
571struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id)
572{
573 struct sst_module *module;
574
575 mutex_lock(&dsp->mutex);
576
577 list_for_each_entry(module, &dsp->module_list, list) {
578 if (module->id == id) {
579 mutex_unlock(&dsp->mutex);
580 return module;
581 }
582 }
583
584 mutex_unlock(&dsp->mutex);
585 return NULL;
586}
587EXPORT_SYMBOL_GPL(sst_module_get_from_id);
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c
new file mode 100644
index 000000000000..f5ebf36af889
--- /dev/null
+++ b/sound/soc/intel/sst-haswell-dsp.c
@@ -0,0 +1,517 @@
1/*
2 * Intel Haswell SST DSP driver
3 *
4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/delay.h>
18#include <linux/fs.h>
19#include <linux/slab.h>
20#include <linux/device.h>
21#include <linux/sched.h>
22#include <linux/export.h>
23#include <linux/interrupt.h>
24#include <linux/module.h>
25#include <linux/dma-mapping.h>
26#include <linux/platform_device.h>
27#include <linux/pci.h>
28#include <linux/firmware.h>
29#include <linux/pm_runtime.h>
30
31#include <linux/acpi.h>
32#include <acpi/acpi_bus.h>
33
34#include "sst-dsp.h"
35#include "sst-dsp-priv.h"
36#include "sst-haswell-ipc.h"
37
38#include <trace/events/hswadsp.h>
39
40#define SST_HSW_FW_SIGNATURE_SIZE 4
41#define SST_HSW_FW_SIGN "$SST"
42#define SST_HSW_FW_LIB_SIGN "$LIB"
43
44#define SST_WPT_SHIM_OFFSET 0xFB000
45#define SST_LP_SHIM_OFFSET 0xE7000
46#define SST_WPT_IRAM_OFFSET 0xA0000
47#define SST_LP_IRAM_OFFSET 0x80000
48
49#define SST_SHIM_PM_REG 0x84
50
51#define SST_HSW_IRAM 1
52#define SST_HSW_DRAM 2
53#define SST_HSW_REGS 3
54
55struct dma_block_info {
56 __le32 type; /* IRAM/DRAM */
57 __le32 size; /* Bytes */
58 __le32 ram_offset; /* Offset in I/DRAM */
59 __le32 rsvd; /* Reserved field */
60} __attribute__((packed));
61
62struct fw_module_info {
63 __le32 persistent_size;
64 __le32 scratch_size;
65} __attribute__((packed));
66
67struct fw_header {
68 unsigned char signature[SST_HSW_FW_SIGNATURE_SIZE]; /* FW signature */
69 __le32 file_size; /* size of fw minus this header */
70 __le32 modules; /* # of modules */
71 __le32 file_format; /* version of header format */
72 __le32 reserved[4];
73} __attribute__((packed));
74
75struct fw_module_header {
76 unsigned char signature[SST_HSW_FW_SIGNATURE_SIZE]; /* module signature */
77 __le32 mod_size; /* size of module */
78 __le32 blocks; /* # of blocks */
79 __le16 padding;
80 __le16 type; /* codec type, pp lib */
81 __le32 entry_point;
82 struct fw_module_info info;
83} __attribute__((packed));
84
85static void hsw_free(struct sst_dsp *sst);
86
87static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
88 struct fw_module_header *module)
89{
90 struct dma_block_info *block;
91 struct sst_module *mod;
92 struct sst_module_data block_data;
93 struct sst_module_template template;
94 int count;
95 void __iomem *ram;
96
97 /* TODO: allowed module types need to be configurable */
98 if (module->type != SST_HSW_MODULE_BASE_FW
99 && module->type != SST_HSW_MODULE_PCM_SYSTEM
100 && module->type != SST_HSW_MODULE_PCM
101 && module->type != SST_HSW_MODULE_PCM_REFERENCE
102 && module->type != SST_HSW_MODULE_PCM_CAPTURE
103 && module->type != SST_HSW_MODULE_LPAL)
104 return 0;
105
106 dev_dbg(dsp->dev, "new module sign 0x%s size 0x%x blocks 0x%x type 0x%x\n",
107 module->signature, module->mod_size,
108 module->blocks, module->type);
109 dev_dbg(dsp->dev, " entrypoint 0x%x\n", module->entry_point);
110 dev_dbg(dsp->dev, " persistent 0x%x scratch 0x%x\n",
111 module->info.persistent_size, module->info.scratch_size);
112
113 memset(&template, 0, sizeof(template));
114 template.id = module->type;
115 template.entry = module->entry_point;
116 template.p.size = module->info.persistent_size;
117 template.p.type = SST_MEM_DRAM;
118 template.p.data_type = SST_DATA_P;
119 template.s.size = module->info.scratch_size;
120 template.s.type = SST_MEM_DRAM;
121 template.s.data_type = SST_DATA_S;
122
123 mod = sst_module_new(fw, &template, NULL);
124 if (mod == NULL)
125 return -ENOMEM;
126
127 block = (void *)module + sizeof(*module);
128
129 for (count = 0; count < module->blocks; count++) {
130
131 if (block->size <= 0) {
132 dev_err(dsp->dev,
133 "error: block %d size invalid\n", count);
134 sst_module_free(mod);
135 return -EINVAL;
136 }
137
138 switch (block->type) {
139 case SST_HSW_IRAM:
140 ram = dsp->addr.lpe;
141 block_data.offset =
142 block->ram_offset + dsp->addr.iram_offset;
143 block_data.type = SST_MEM_IRAM;
144 break;
145 case SST_HSW_DRAM:
146 ram = dsp->addr.lpe;
147 block_data.offset = block->ram_offset;
148 block_data.type = SST_MEM_DRAM;
149 break;
150 default:
151 dev_err(dsp->dev, "error: bad type 0x%x for block 0x%x\n",
152 block->type, count);
153 sst_module_free(mod);
154 return -EINVAL;
155 }
156
157 block_data.size = block->size;
158 block_data.data_type = SST_DATA_M;
159 block_data.data = (void *)block + sizeof(*block);
160 block_data.data_offset = block_data.data - fw->dma_buf;
161
162 dev_dbg(dsp->dev, "copy firmware block %d type 0x%x "
163 "size 0x%x ==> ram %p offset 0x%x\n",
164 count, block->type, block->size, ram,
165 block->ram_offset);
166
167 sst_module_insert_fixed_block(mod, &block_data);
168
169 block = (void *)block + sizeof(*block) + block->size;
170 }
171 return 0;
172}
173
174static int hsw_parse_fw_image(struct sst_fw *sst_fw)
175{
176 struct fw_header *header;
177 struct sst_module *scratch;
178 struct fw_module_header *module;
179 struct sst_dsp *dsp = sst_fw->dsp;
180 struct sst_hsw *hsw = sst_fw->private;
181 int ret, count;
182
183 /* Read the header information from the data pointer */
184 header = (struct fw_header *)sst_fw->dma_buf;
185
186 /* verify FW */
187 if ((strncmp(header->signature, SST_HSW_FW_SIGN, 4) != 0) ||
188 (sst_fw->size != header->file_size + sizeof(*header))) {
189 dev_err(dsp->dev, "error: invalid fw sign/filesize mismatch\n");
190 return -EINVAL;
191 }
192
193 dev_dbg(dsp->dev, "header size=0x%x modules=0x%x fmt=0x%x size=%zu\n",
194 header->file_size, header->modules,
195 header->file_format, sizeof(*header));
196
197 /* parse each module */
198 module = (void *)sst_fw->dma_buf + sizeof(*header);
199 for (count = 0; count < header->modules; count++) {
200
201 /* module */
202 ret = hsw_parse_module(dsp, sst_fw, module);
203 if (ret < 0) {
204 dev_err(dsp->dev, "error: invalid module %d\n", count);
205 return ret;
206 }
207 module = (void *)module + sizeof(*module) + module->mod_size;
208 }
209
210 /* allocate persistent/scratch mem regions */
211 scratch = sst_mem_block_alloc_scratch(dsp);
212 if (scratch == NULL)
213 return -ENOMEM;
214
215 sst_hsw_set_scratch_module(hsw, scratch);
216
217 return 0;
218}
219
220static irqreturn_t hsw_irq(int irq, void *context)
221{
222 struct sst_dsp *sst = (struct sst_dsp *) context;
223 u32 isr;
224 int ret = IRQ_NONE;
225
226 spin_lock(&sst->spinlock);
227
228 /* Interrupt arrived, check src */
229 isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX);
230 if (isr & SST_ISRX_DONE) {
231 trace_sst_irq_done(isr,
232 sst_dsp_shim_read_unlocked(sst, SST_IMRX));
233
234 /* Mask Done interrupt before return */
235 sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
236 SST_IMRX_DONE, SST_IMRX_DONE);
237 ret = IRQ_WAKE_THREAD;
238 }
239
240 if (isr & SST_ISRX_BUSY) {
241 trace_sst_irq_busy(isr,
242 sst_dsp_shim_read_unlocked(sst, SST_IMRX));
243
244 /* Mask Busy interrupt before return */
245 sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
246 SST_IMRX_BUSY, SST_IMRX_BUSY);
247 ret = IRQ_WAKE_THREAD;
248 }
249
250 spin_unlock(&sst->spinlock);
251 return ret;
252}
253
254static void hsw_boot(struct sst_dsp *sst)
255{
256 /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */
257 sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
258 SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0);
259
260 /* stall DSP core, set clk to 192/96Mhz */
261 sst_dsp_shim_update_bits_unlocked(sst,
262 SST_CSR, SST_CSR_STALL | SST_CSR_DCS_MASK,
263 SST_CSR_STALL | SST_CSR_DCS(4));
264
265 /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */
266 sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
267 SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0,
268 SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0);
269
270 /* disable DMA finish function for SSP0 & SSP1 */
271 sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1,
272 SST_CSR2_SDFD_SSP1);
273
274 /* enable DMA engine 0,1 all channels to access host memory */
275 sst_dsp_shim_update_bits_unlocked(sst, SST_HDMC,
276 SST_HDMC_HDDA1(0xff) | SST_HDMC_HDDA0(0xff),
277 SST_HDMC_HDDA1(0xff) | SST_HDMC_HDDA0(0xff));
278
279 /* disable all clock gating */
280 writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2);
281
282 /* set DSP to RUN */
283 sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0);
284}
285
286static void hsw_reset(struct sst_dsp *sst)
287{
288 /* put DSP into reset and stall */
289 sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
290 SST_CSR_RST | SST_CSR_STALL, SST_CSR_RST | SST_CSR_STALL);
291
292 /* keep in reset for 10ms */
293 mdelay(10);
294
295 /* take DSP out of reset and keep stalled for FW loading */
296 sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
297 SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
298}
299
300struct sst_adsp_memregion {
301 u32 start;
302 u32 end;
303 int blocks;
304 enum sst_mem_type type;
305};
306
307/* lynx point ADSP mem regions */
308static const struct sst_adsp_memregion lp_region[] = {
309 {0x00000, 0x40000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
310 {0x40000, 0x80000, 8, SST_MEM_DRAM}, /* D-SRAM1 - 8 * 32kB */
311 {0x80000, 0xE0000, 12, SST_MEM_IRAM}, /* I-SRAM - 12 * 32kB */
312};
313
314/* wild cat point ADSP mem regions */
315static const struct sst_adsp_memregion wpt_region[] = {
316 {0x00000, 0x40000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */
317 {0x40000, 0x80000, 8, SST_MEM_DRAM}, /* D-SRAM1 - 8 * 32kB */
318 {0x80000, 0xA0000, 4, SST_MEM_DRAM}, /* D-SRAM2 - 4 * 32kB */
319 {0xA0000, 0xF0000, 10, SST_MEM_IRAM}, /* I-SRAM - 10 * 32kB */
320};
321
322static int hsw_acpi_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata)
323{
324 /* ADSP DRAM & IRAM */
325 sst->addr.lpe_base = pdata->lpe_base;
326 sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size);
327 if (!sst->addr.lpe)
328 return -ENODEV;
329
330 /* ADSP PCI MMIO config space */
331 sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size);
332 if (!sst->addr.pci_cfg) {
333 iounmap(sst->addr.lpe);
334 return -ENODEV;
335 }
336
337 /* SST Shim */
338 sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset;
339 return 0;
340}
341
342static u32 hsw_block_get_bit(struct sst_mem_block *block)
343{
344 u32 bit = 0, shift = 0;
345
346 switch (block->type) {
347 case SST_MEM_DRAM:
348 shift = 16;
349 break;
350 case SST_MEM_IRAM:
351 shift = 6;
352 break;
353 default:
354 return 0;
355 }
356
357 bit = 1 << (block->index + shift);
358
359 return bit;
360}
361
362/* enable 32kB memory block - locks held by caller */
363static int hsw_block_enable(struct sst_mem_block *block)
364{
365 struct sst_dsp *sst = block->dsp;
366 u32 bit, val;
367
368 if (block->users++ > 0)
369 return 0;
370
371 dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n",
372 block->type, block->index, block->offset);
373
374 val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
375 bit = hsw_block_get_bit(block);
376 writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0);
377
378 /* wait 18 DSP clock ticks */
379 udelay(10);
380
381 return 0;
382}
383
384/* disable 32kB memory block - locks held by caller */
385static int hsw_block_disable(struct sst_mem_block *block)
386{
387 struct sst_dsp *sst = block->dsp;
388 u32 bit, val;
389
390 if (--block->users > 0)
391 return 0;
392
393 dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n",
394 block->type, block->index, block->offset);
395
396 val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
397 bit = hsw_block_get_bit(block);
398 writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
399
400 return 0;
401}
402
403static struct sst_block_ops sst_hsw_ops = {
404 .enable = hsw_block_enable,
405 .disable = hsw_block_disable,
406};
407
408static int hsw_enable_shim(struct sst_dsp *sst)
409{
410 int tries = 10;
411 u32 reg;
412
413 /* enable shim */
414 reg = readl(sst->addr.pci_cfg + SST_SHIM_PM_REG);
415 writel(reg & ~0x3, sst->addr.pci_cfg + SST_SHIM_PM_REG);
416
417 /* check that ADSP shim is enabled */
418 while (tries--) {
419 reg = sst_dsp_shim_read_unlocked(sst, SST_CSR);
420 if (reg != 0xffffffff)
421 return 0;
422
423 msleep(1);
424 }
425
426 return -ENODEV;
427}
428
429static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
430{
431 const struct sst_adsp_memregion *region;
432 struct device *dev;
433 int ret = -ENODEV, i, j, region_count;
434 u32 offset, size;
435
436 dev = sst->dev;
437
438 switch (sst->id) {
439 case SST_DEV_ID_LYNX_POINT:
440 region = lp_region;
441 region_count = ARRAY_SIZE(lp_region);
442 sst->addr.iram_offset = SST_LP_IRAM_OFFSET;
443 sst->addr.shim_offset = SST_LP_SHIM_OFFSET;
444 break;
445 case SST_DEV_ID_WILDCAT_POINT:
446 region = wpt_region;
447 region_count = ARRAY_SIZE(wpt_region);
448 sst->addr.iram_offset = SST_WPT_IRAM_OFFSET;
449 sst->addr.shim_offset = SST_WPT_SHIM_OFFSET;
450 break;
451 default:
452 dev_err(dev, "error: failed to get mem resources\n");
453 return ret;
454 }
455
456 ret = hsw_acpi_resource_map(sst, pdata);
457 if (ret < 0) {
458 dev_err(dev, "error: failed to map resources\n");
459 return ret;
460 }
461
462 /* enable the DSP SHIM */
463 ret = hsw_enable_shim(sst);
464 if (ret < 0) {
465 dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n");
466 return ret;
467 }
468
469 ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
470 if (ret)
471 return ret;
472
473 /* Enable Interrupt from both sides */
474 sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, 0x3, 0x0);
475 sst_dsp_shim_update_bits_unlocked(sst, SST_IMRD,
476 (0x3 | 0x1 << 16 | 0x3 << 21), 0x0);
477
478 /* register DSP memory blocks - ideally we should get this from ACPI */
479 for (i = 0; i < region_count; i++) {
480 offset = region[i].start;
481 size = (region[i].end - region[i].start) / region[i].blocks;
482
483 /* register individual memory blocks */
484 for (j = 0; j < region[i].blocks; j++) {
485 sst_mem_block_register(sst, offset, size,
486 region[i].type, &sst_hsw_ops, j, sst);
487 offset += size;
488 }
489 }
490
491 /* set default power gating mask */
492 writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL0);
493
494 return 0;
495}
496
497static void hsw_free(struct sst_dsp *sst)
498{
499 sst_mem_block_unregister_all(sst);
500 iounmap(sst->addr.lpe);
501 iounmap(sst->addr.pci_cfg);
502}
503
504struct sst_ops haswell_ops = {
505 .reset = hsw_reset,
506 .boot = hsw_boot,
507 .write = sst_shim32_write,
508 .read = sst_shim32_read,
509 .write64 = sst_shim32_write64,
510 .read64 = sst_shim32_read64,
511 .ram_read = sst_memcpy_fromio_32,
512 .ram_write = sst_memcpy_toio_32,
513 .irq_handler = hsw_irq,
514 .init = hsw_init,
515 .free = hsw_free,
516 .parse_fw = hsw_parse_fw_image,
517};
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
new file mode 100644
index 000000000000..f46bb4ddde6f
--- /dev/null
+++ b/sound/soc/intel/sst-haswell-ipc.c
@@ -0,0 +1,1785 @@
1/*
2 * Intel SST Haswell/Broadwell IPC Support
3 *
4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/types.h>
18#include <linux/kernel.h>
19#include <linux/list.h>
20#include <linux/device.h>
21#include <linux/wait.h>
22#include <linux/spinlock.h>
23#include <linux/workqueue.h>
24#include <linux/export.h>
25#include <linux/slab.h>
26#include <linux/delay.h>
27#include <linux/sched.h>
28#include <linux/list.h>
29#include <linux/platform_device.h>
30#include <linux/kthread.h>
31#include <linux/firmware.h>
32#include <linux/dma-mapping.h>
33#include <linux/debugfs.h>
34
35#include "sst-haswell-ipc.h"
36#include "sst-dsp.h"
37#include "sst-dsp-priv.h"
38
39/* Global Message - Generic */
40#define IPC_GLB_TYPE_SHIFT 24
41#define IPC_GLB_TYPE_MASK (0x1f << IPC_GLB_TYPE_SHIFT)
42#define IPC_GLB_TYPE(x) (x << IPC_GLB_TYPE_SHIFT)
43
44/* Global Message - Reply */
45#define IPC_GLB_REPLY_SHIFT 0
46#define IPC_GLB_REPLY_MASK (0x1f << IPC_GLB_REPLY_SHIFT)
47#define IPC_GLB_REPLY_TYPE(x) (x << IPC_GLB_REPLY_TYPE_SHIFT)
48
49/* Stream Message - Generic */
50#define IPC_STR_TYPE_SHIFT 20
51#define IPC_STR_TYPE_MASK (0xf << IPC_STR_TYPE_SHIFT)
52#define IPC_STR_TYPE(x) (x << IPC_STR_TYPE_SHIFT)
53#define IPC_STR_ID_SHIFT 16
54#define IPC_STR_ID_MASK (0xf << IPC_STR_ID_SHIFT)
55#define IPC_STR_ID(x) (x << IPC_STR_ID_SHIFT)
56
57/* Stream Message - Reply */
58#define IPC_STR_REPLY_SHIFT 0
59#define IPC_STR_REPLY_MASK (0x1f << IPC_STR_REPLY_SHIFT)
60
61/* Stream Stage Message - Generic */
62#define IPC_STG_TYPE_SHIFT 12
63#define IPC_STG_TYPE_MASK (0xf << IPC_STG_TYPE_SHIFT)
64#define IPC_STG_TYPE(x) (x << IPC_STG_TYPE_SHIFT)
65#define IPC_STG_ID_SHIFT 10
66#define IPC_STG_ID_MASK (0x3 << IPC_STG_ID_SHIFT)
67#define IPC_STG_ID(x) (x << IPC_STG_ID_SHIFT)
68
69/* Stream Stage Message - Reply */
70#define IPC_STG_REPLY_SHIFT 0
71#define IPC_STG_REPLY_MASK (0x1f << IPC_STG_REPLY_SHIFT)
72
73/* Debug Log Message - Generic */
74#define IPC_LOG_OP_SHIFT 20
75#define IPC_LOG_OP_MASK (0xf << IPC_LOG_OP_SHIFT)
76#define IPC_LOG_OP_TYPE(x) (x << IPC_LOG_OP_SHIFT)
77#define IPC_LOG_ID_SHIFT 16
78#define IPC_LOG_ID_MASK (0xf << IPC_LOG_ID_SHIFT)
79#define IPC_LOG_ID(x) (x << IPC_LOG_ID_SHIFT)
80
81/* IPC message timeout (msecs) */
82#define IPC_TIMEOUT_MSECS 300
83#define IPC_BOOT_MSECS 200
84#define IPC_MSG_WAIT 0
85#define IPC_MSG_NOWAIT 1
86
87/* Firmware Ready Message */
88#define IPC_FW_READY (0x1 << 29)
89#define IPC_STATUS_MASK (0x3 << 30)
90
91#define IPC_EMPTY_LIST_SIZE 8
92#define IPC_MAX_STREAMS 4
93
94/* Mailbox */
95#define IPC_MAX_MAILBOX_BYTES 256
96
97/* Global Message - Types and Replies */
98enum ipc_glb_type {
99 IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */
100 IPC_GLB_PERFORMANCE_MONITOR = 1, /* Performance monitoring actions */
101 IPC_GLB_ALLOCATE_STREAM = 3, /* Request to allocate new stream */
102 IPC_GLB_FREE_STREAM = 4, /* Request to free stream */
103 IPC_GLB_GET_FW_CAPABILITIES = 5, /* Retrieves firmware capabilities */
104 IPC_GLB_STREAM_MESSAGE = 6, /* Message directed to stream or its stages */
105 /* Request to store firmware context during D0->D3 transition */
106 IPC_GLB_REQUEST_DUMP = 7,
107 /* Request to restore firmware context during D3->D0 transition */
108 IPC_GLB_RESTORE_CONTEXT = 8,
109 IPC_GLB_GET_DEVICE_FORMATS = 9, /* Set device format */
110 IPC_GLB_SET_DEVICE_FORMATS = 10, /* Get device format */
111 IPC_GLB_SHORT_REPLY = 11,
112 IPC_GLB_ENTER_DX_STATE = 12,
113 IPC_GLB_GET_MIXER_STREAM_INFO = 13, /* Request mixer stream params */
114 IPC_GLB_DEBUG_LOG_MESSAGE = 14, /* Message to or from the debug logger. */
115 IPC_GLB_REQUEST_TRANSFER = 16, /* < Request Transfer for host */
116 IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17, /* Maximum message number */
117};
118
119enum ipc_glb_reply {
120 IPC_GLB_REPLY_SUCCESS = 0, /* The operation was successful. */
121 IPC_GLB_REPLY_ERROR_INVALID_PARAM = 1, /* Invalid parameter was passed. */
122 IPC_GLB_REPLY_UNKNOWN_MESSAGE_TYPE = 2, /* Uknown message type was resceived. */
123 IPC_GLB_REPLY_OUT_OF_RESOURCES = 3, /* No resources to satisfy the request. */
124 IPC_GLB_REPLY_BUSY = 4, /* The system or resource is busy. */
125 IPC_GLB_REPLY_PENDING = 5, /* The action was scheduled for processing. */
126 IPC_GLB_REPLY_FAILURE = 6, /* Critical error happened. */
127 IPC_GLB_REPLY_INVALID_REQUEST = 7, /* Request can not be completed. */
128 IPC_GLB_REPLY_STAGE_UNINITIALIZED = 8, /* Processing stage was uninitialized. */
129 IPC_GLB_REPLY_NOT_FOUND = 9, /* Required resource can not be found. */
130 IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10, /* Source was not started. */
131};
132
133/* Stream Message - Types */
134enum ipc_str_operation {
135 IPC_STR_RESET = 0,
136 IPC_STR_PAUSE = 1,
137 IPC_STR_RESUME = 2,
138 IPC_STR_STAGE_MESSAGE = 3,
139 IPC_STR_NOTIFICATION = 4,
140 IPC_STR_MAX_MESSAGE
141};
142
143/* Stream Stage Message Types */
144enum ipc_stg_operation {
145 IPC_STG_GET_VOLUME = 0,
146 IPC_STG_SET_VOLUME,
147 IPC_STG_SET_WRITE_POSITION,
148 IPC_STG_SET_FX_ENABLE,
149 IPC_STG_SET_FX_DISABLE,
150 IPC_STG_SET_FX_GET_PARAM,
151 IPC_STG_SET_FX_SET_PARAM,
152 IPC_STG_SET_FX_GET_INFO,
153 IPC_STG_MUTE_LOOPBACK,
154 IPC_STG_MAX_MESSAGE
155};
156
157/* Stream Stage Message Types For Notification*/
158enum ipc_stg_operation_notify {
159 IPC_POSITION_CHANGED = 0,
160 IPC_STG_GLITCH,
161 IPC_STG_MAX_NOTIFY
162};
163
164enum ipc_glitch_type {
165 IPC_GLITCH_UNDERRUN = 1,
166 IPC_GLITCH_DECODER_ERROR,
167 IPC_GLITCH_DOUBLED_WRITE_POS,
168 IPC_GLITCH_MAX
169};
170
171/* Debug Control */
172enum ipc_debug_operation {
173 IPC_DEBUG_ENABLE_LOG = 0,
174 IPC_DEBUG_DISABLE_LOG = 1,
175 IPC_DEBUG_REQUEST_LOG_DUMP = 2,
176 IPC_DEBUG_NOTIFY_LOG_DUMP = 3,
177 IPC_DEBUG_MAX_DEBUG_LOG
178};
179
180/* Firmware Ready */
181struct sst_hsw_ipc_fw_ready {
182 u32 inbox_offset;
183 u32 outbox_offset;
184 u32 inbox_size;
185 u32 outbox_size;
186 u32 fw_info_size;
187 u8 fw_info[1];
188} __attribute__((packed));
189
190struct ipc_message {
191 struct list_head list;
192 u32 header;
193
194 /* direction wrt host CPU */
195 char tx_data[IPC_MAX_MAILBOX_BYTES];
196 size_t tx_size;
197 char rx_data[IPC_MAX_MAILBOX_BYTES];
198 size_t rx_size;
199
200 wait_queue_head_t waitq;
201 bool pending;
202 bool complete;
203 bool wait;
204 int errno;
205};
206
207struct sst_hsw_stream;
208struct sst_hsw;
209
210/* Stream infomation */
211struct sst_hsw_stream {
212 /* configuration */
213 struct sst_hsw_ipc_stream_alloc_req request;
214 struct sst_hsw_ipc_stream_alloc_reply reply;
215 struct sst_hsw_ipc_stream_free_req free_req;
216
217 /* Mixer info */
218 u32 mute_volume[SST_HSW_NO_CHANNELS];
219 u32 mute[SST_HSW_NO_CHANNELS];
220
221 /* runtime info */
222 struct sst_hsw *hsw;
223 int host_id;
224 bool commited;
225 bool running;
226
227 /* Notification work */
228 struct work_struct notify_work;
229 u32 header;
230
231 /* Position info from DSP */
232 struct sst_hsw_ipc_stream_set_position wpos;
233 struct sst_hsw_ipc_stream_get_position rpos;
234 struct sst_hsw_ipc_stream_glitch_position glitch;
235
236 /* Volume info */
237 struct sst_hsw_ipc_volume_req vol_req;
238
239 /* driver callback */
240 u32 (*notify_position)(struct sst_hsw_stream *stream, void *data);
241 void *pdata;
242
243 struct list_head node;
244};
245
246/* FW log ring information */
247struct sst_hsw_log_stream {
248 dma_addr_t dma_addr;
249 unsigned char *dma_area;
250 unsigned char *ring_descr;
251 int pages;
252 int size;
253
254 /* Notification work */
255 struct work_struct notify_work;
256 wait_queue_head_t readers_wait_q;
257 struct mutex rw_mutex;
258
259 u32 last_pos;
260 u32 curr_pos;
261 u32 reader_pos;
262
263 /* fw log config */
264 u32 config[SST_HSW_FW_LOG_CONFIG_DWORDS];
265
266 struct sst_hsw *hsw;
267};
268
269/* SST Haswell IPC data */
270struct sst_hsw {
271 struct device *dev;
272 struct sst_dsp *dsp;
273 struct platform_device *pdev_pcm;
274
275 /* FW config */
276 struct sst_hsw_ipc_fw_ready fw_ready;
277 struct sst_hsw_ipc_fw_version version;
278 struct sst_module *scratch;
279 bool fw_done;
280
281 /* stream */
282 struct list_head stream_list;
283
284 /* global mixer */
285 struct sst_hsw_ipc_stream_info_reply mixer_info;
286 enum sst_hsw_volume_curve curve_type;
287 u32 curve_duration;
288 u32 mute[SST_HSW_NO_CHANNELS];
289 u32 mute_volume[SST_HSW_NO_CHANNELS];
290
291 /* DX */
292 struct sst_hsw_ipc_dx_reply dx;
293
294 /* boot */
295 wait_queue_head_t boot_wait;
296 bool boot_complete;
297 bool shutdown;
298
299 /* IPC messaging */
300 struct list_head tx_list;
301 struct list_head rx_list;
302 struct list_head empty_list;
303 wait_queue_head_t wait_txq;
304 struct task_struct *tx_thread;
305 struct kthread_worker kworker;
306 struct kthread_work kwork;
307 bool pending;
308 struct ipc_message *msg;
309
310 /* FW log stream */
311 struct sst_hsw_log_stream log_stream;
312};
313
314#define CREATE_TRACE_POINTS
315#include <trace/events/hswadsp.h>
316
317static inline u32 msg_get_global_type(u32 msg)
318{
319 return (msg & IPC_GLB_TYPE_MASK) >> IPC_GLB_TYPE_SHIFT;
320}
321
322static inline u32 msg_get_global_reply(u32 msg)
323{
324 return (msg & IPC_GLB_REPLY_MASK) >> IPC_GLB_REPLY_SHIFT;
325}
326
327static inline u32 msg_get_stream_type(u32 msg)
328{
329 return (msg & IPC_STR_TYPE_MASK) >> IPC_STR_TYPE_SHIFT;
330}
331
332static inline u32 msg_get_stage_type(u32 msg)
333{
334 return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT;
335}
336
337static inline u32 msg_set_stage_type(u32 msg, u32 type)
338{
339 return (msg & ~IPC_STG_TYPE_MASK) +
340 (type << IPC_STG_TYPE_SHIFT);
341}
342
343static inline u32 msg_get_stream_id(u32 msg)
344{
345 return (msg & IPC_STR_ID_MASK) >> IPC_STR_ID_SHIFT;
346}
347
348static inline u32 msg_get_notify_reason(u32 msg)
349{
350 return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT;
351}
352
353u32 create_channel_map(enum sst_hsw_channel_config config)
354{
355 switch (config) {
356 case SST_HSW_CHANNEL_CONFIG_MONO:
357 return (0xFFFFFFF0 | SST_HSW_CHANNEL_CENTER);
358 case SST_HSW_CHANNEL_CONFIG_STEREO:
359 return (0xFFFFFF00 | SST_HSW_CHANNEL_LEFT
360 | (SST_HSW_CHANNEL_RIGHT << 4));
361 case SST_HSW_CHANNEL_CONFIG_2_POINT_1:
362 return (0xFFFFF000 | SST_HSW_CHANNEL_LEFT
363 | (SST_HSW_CHANNEL_RIGHT << 4)
364 | (SST_HSW_CHANNEL_LFE << 8 ));
365 case SST_HSW_CHANNEL_CONFIG_3_POINT_0:
366 return (0xFFFFF000 | SST_HSW_CHANNEL_LEFT
367 | (SST_HSW_CHANNEL_CENTER << 4)
368 | (SST_HSW_CHANNEL_RIGHT << 8));
369 case SST_HSW_CHANNEL_CONFIG_3_POINT_1:
370 return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
371 | (SST_HSW_CHANNEL_CENTER << 4)
372 | (SST_HSW_CHANNEL_RIGHT << 8)
373 | (SST_HSW_CHANNEL_LFE << 12));
374 case SST_HSW_CHANNEL_CONFIG_QUATRO:
375 return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
376 | (SST_HSW_CHANNEL_RIGHT << 4)
377 | (SST_HSW_CHANNEL_LEFT_SURROUND << 8)
378 | (SST_HSW_CHANNEL_RIGHT_SURROUND << 12));
379 case SST_HSW_CHANNEL_CONFIG_4_POINT_0:
380 return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT
381 | (SST_HSW_CHANNEL_CENTER << 4)
382 | (SST_HSW_CHANNEL_RIGHT << 8)
383 | (SST_HSW_CHANNEL_CENTER_SURROUND << 12));
384 case SST_HSW_CHANNEL_CONFIG_5_POINT_0:
385 return (0xFFF00000 | SST_HSW_CHANNEL_LEFT
386 | (SST_HSW_CHANNEL_CENTER << 4)
387 | (SST_HSW_CHANNEL_RIGHT << 8)
388 | (SST_HSW_CHANNEL_LEFT_SURROUND << 12)
389 | (SST_HSW_CHANNEL_RIGHT_SURROUND << 16));
390 case SST_HSW_CHANNEL_CONFIG_5_POINT_1:
391 return (0xFF000000 | SST_HSW_CHANNEL_CENTER
392 | (SST_HSW_CHANNEL_LEFT << 4)
393 | (SST_HSW_CHANNEL_RIGHT << 8)
394 | (SST_HSW_CHANNEL_LEFT_SURROUND << 12)
395 | (SST_HSW_CHANNEL_RIGHT_SURROUND << 16)
396 | (SST_HSW_CHANNEL_LFE << 20));
397 case SST_HSW_CHANNEL_CONFIG_DUAL_MONO:
398 return (0xFFFFFF00 | SST_HSW_CHANNEL_LEFT
399 | (SST_HSW_CHANNEL_LEFT << 4));
400 default:
401 return 0xFFFFFFFF;
402 }
403}
404
405static struct sst_hsw_stream *get_stream_by_id(struct sst_hsw *hsw,
406 int stream_id)
407{
408 struct sst_hsw_stream *stream;
409
410 list_for_each_entry(stream, &hsw->stream_list, node) {
411 if (stream->reply.stream_hw_id == stream_id)
412 return stream;
413 }
414
415 return NULL;
416}
417
418static void ipc_shim_dbg(struct sst_hsw *hsw, const char *text)
419{
420 struct sst_dsp *sst = hsw->dsp;
421 u32 isr, ipcd, imrx, ipcx;
422
423 ipcx = sst_dsp_shim_read_unlocked(sst, SST_IPCX);
424 isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX);
425 ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
426 imrx = sst_dsp_shim_read_unlocked(sst, SST_IMRX);
427
428 dev_err(hsw->dev, "ipc: --%s-- ipcx 0x%8.8x isr 0x%8.8x ipcd 0x%8.8x imrx 0x%8.8x\n",
429 text, ipcx, isr, ipcd, imrx);
430}
431
432/* locks held by caller */
433static struct ipc_message *msg_get_empty(struct sst_hsw *hsw)
434{
435 struct ipc_message *msg = NULL;
436
437 if (!list_empty(&hsw->empty_list)) {
438 msg = list_first_entry(&hsw->empty_list, struct ipc_message,
439 list);
440 list_del(&msg->list);
441 }
442
443 return msg;
444}
445
446static void ipc_tx_msgs(struct kthread_work *work)
447{
448 struct sst_hsw *hsw =
449 container_of(work, struct sst_hsw, kwork);
450 struct ipc_message *msg;
451 unsigned long flags;
452 u32 ipcx;
453
454 spin_lock_irqsave(&hsw->dsp->spinlock, flags);
455
456 if (list_empty(&hsw->tx_list) || hsw->pending) {
457 spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
458 return;
459 }
460
461 /* if the DSP is busy we will TX messages after IRQ */
462 ipcx = sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX);
463 if (ipcx & SST_IPCX_BUSY) {
464 spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
465 return;
466 }
467
468 msg = list_first_entry(&hsw->tx_list, struct ipc_message, list);
469
470 list_move(&msg->list, &hsw->rx_list);
471
472 /* send the message */
473 sst_dsp_outbox_write(hsw->dsp, msg->tx_data, msg->tx_size);
474 sst_dsp_ipc_msg_tx(hsw->dsp, msg->header | SST_IPCX_BUSY);
475
476 spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
477}
478
479/* locks held by caller */
480static void tx_msg_reply_complete(struct sst_hsw *hsw, struct ipc_message *msg)
481{
482 msg->complete = true;
483 trace_ipc_reply("completed", msg->header);
484
485 if (!msg->wait)
486 list_add_tail(&msg->list, &hsw->empty_list);
487 else
488 wake_up(&msg->waitq);
489}
490
491static int tx_wait_done(struct sst_hsw *hsw, struct ipc_message *msg,
492 void *rx_data)
493{
494 unsigned long flags;
495 int ret;
496
497 /* wait for DSP completion (in all cases atm inc pending) */
498 ret = wait_event_timeout(msg->waitq, msg->complete,
499 msecs_to_jiffies(IPC_TIMEOUT_MSECS));
500
501 spin_lock_irqsave(&hsw->dsp->spinlock, flags);
502 if (ret == 0) {
503 ipc_shim_dbg(hsw, "message timeout");
504
505 trace_ipc_error("error message timeout for", msg->header);
506 ret = -ETIMEDOUT;
507 } else {
508
509 /* copy the data returned from DSP */
510 if (msg->rx_size)
511 memcpy(rx_data, msg->rx_data, msg->rx_size);
512 ret = msg->errno;
513 }
514
515 list_add_tail(&msg->list, &hsw->empty_list);
516 spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
517 return ret;
518}
519
520static int ipc_tx_message(struct sst_hsw *hsw, u32 header, void *tx_data,
521 size_t tx_bytes, void *rx_data, size_t rx_bytes, int wait)
522{
523 struct ipc_message *msg;
524 unsigned long flags;
525
526 spin_lock_irqsave(&hsw->dsp->spinlock, flags);
527
528 msg = msg_get_empty(hsw);
529 if (msg == NULL) {
530 spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
531 return -EBUSY;
532 }
533
534 if (tx_bytes)
535 memcpy(msg->tx_data, tx_data, tx_bytes);
536
537 msg->header = header;
538 msg->tx_size = tx_bytes;
539 msg->rx_size = rx_bytes;
540 msg->wait = wait;
541 msg->errno = 0;
542 msg->pending = false;
543 msg->complete = false;
544
545 list_add_tail(&msg->list, &hsw->tx_list);
546 spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
547
548 queue_kthread_work(&hsw->kworker, &hsw->kwork);
549
550 if (wait)
551 return tx_wait_done(hsw, msg, rx_data);
552 else
553 return 0;
554}
555
556static inline int ipc_tx_message_wait(struct sst_hsw *hsw, u32 header,
557 void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes)
558{
559 return ipc_tx_message(hsw, header, tx_data, tx_bytes, rx_data,
560 rx_bytes, 1);
561}
562
563static inline int ipc_tx_message_nowait(struct sst_hsw *hsw, u32 header,
564 void *tx_data, size_t tx_bytes)
565{
566 return ipc_tx_message(hsw, header, tx_data, tx_bytes, NULL, 0, 0);
567}
568
569static void hsw_fw_ready(struct sst_hsw *hsw, u32 header)
570{
571 struct sst_hsw_ipc_fw_ready fw_ready;
572 u32 offset;
573
574 offset = (header & 0x1FFFFFFF) << 3;
575
576 dev_dbg(hsw->dev, "ipc: DSP is ready 0x%8.8x offset %d\n",
577 header, offset);
578
579 /* copy data from the DSP FW ready offset */
580 sst_dsp_read(hsw->dsp, &fw_ready, offset, sizeof(fw_ready));
581
582 sst_dsp_mailbox_init(hsw->dsp, fw_ready.inbox_offset,
583 fw_ready.inbox_size, fw_ready.outbox_offset,
584 fw_ready.outbox_size);
585
586 hsw->boot_complete = true;
587 wake_up(&hsw->boot_wait);
588
589 dev_dbg(hsw->dev, " mailbox upstream 0x%x - size 0x%x\n",
590 fw_ready.inbox_offset, fw_ready.inbox_size);
591 dev_dbg(hsw->dev, " mailbox downstream 0x%x - size 0x%x\n",
592 fw_ready.outbox_offset, fw_ready.outbox_size);
593}
594
595static void hsw_notification_work(struct work_struct *work)
596{
597 struct sst_hsw_stream *stream = container_of(work,
598 struct sst_hsw_stream, notify_work);
599 struct sst_hsw_ipc_stream_glitch_position *glitch = &stream->glitch;
600 struct sst_hsw_ipc_stream_get_position *pos = &stream->rpos;
601 struct sst_hsw *hsw = stream->hsw;
602 u32 reason;
603
604 reason = msg_get_notify_reason(stream->header);
605
606 switch (reason) {
607 case IPC_STG_GLITCH:
608 trace_ipc_notification("DSP stream under/overrun",
609 stream->reply.stream_hw_id);
610 sst_dsp_inbox_read(hsw->dsp, glitch, sizeof(*glitch));
611
612 dev_err(hsw->dev, "glitch %d pos 0x%x write pos 0x%x\n",
613 glitch->glitch_type, glitch->present_pos,
614 glitch->write_pos);
615 break;
616
617 case IPC_POSITION_CHANGED:
618 trace_ipc_notification("DSP stream position changed for",
619 stream->reply.stream_hw_id);
620 sst_dsp_inbox_read(hsw->dsp, pos, sizeof(pos));
621
622 if (stream->notify_position)
623 stream->notify_position(stream, stream->pdata);
624
625 break;
626 default:
627 dev_err(hsw->dev, "error: unknown notification 0x%x\n",
628 stream->header);
629 break;
630 }
631
632 /* tell DSP that notification has been handled */
633 sst_dsp_shim_update_bits_unlocked(hsw->dsp, SST_IPCD,
634 SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
635
636 /* unmask busy interrupt */
637 sst_dsp_shim_update_bits_unlocked(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0);
638}
639
640static struct ipc_message *reply_find_msg(struct sst_hsw *hsw, u32 header)
641{
642 struct ipc_message *msg;
643
644 /* clear reply bits & status bits */
645 header &= ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK);
646
647 if (list_empty(&hsw->rx_list)) {
648 dev_err(hsw->dev, "error: rx list empty but received 0x%x\n",
649 header);
650 return NULL;
651 }
652
653 list_for_each_entry(msg, &hsw->rx_list, list) {
654 if (msg->header == header)
655 return msg;
656 }
657
658 return NULL;
659}
660
661static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg)
662{
663 struct sst_hsw_stream *stream;
664 u32 header = msg->header & ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK);
665 u32 stream_id = msg_get_stream_id(header);
666 u32 stream_msg = msg_get_stream_type(header);
667
668 stream = get_stream_by_id(hsw, stream_id);
669 if (stream == NULL)
670 return;
671
672 switch (stream_msg) {
673 case IPC_STR_STAGE_MESSAGE:
674 case IPC_STR_NOTIFICATION:
675 case IPC_STR_RESET:
676 break;
677 case IPC_STR_PAUSE:
678 stream->running = false;
679 trace_ipc_notification("stream paused",
680 stream->reply.stream_hw_id);
681 break;
682 case IPC_STR_RESUME:
683 stream->running = true;
684 trace_ipc_notification("stream running",
685 stream->reply.stream_hw_id);
686 break;
687 }
688}
689
690static int hsw_process_reply(struct sst_hsw *hsw, u32 header)
691{
692 struct ipc_message *msg;
693 u32 reply = msg_get_global_reply(header);
694
695 trace_ipc_reply("processing -->", header);
696
697 msg = reply_find_msg(hsw, header);
698 if (msg == NULL) {
699 trace_ipc_error("error: can't find message header", header);
700 return -EIO;
701 }
702
703 /* first process the header */
704 switch (reply) {
705 case IPC_GLB_REPLY_PENDING:
706 trace_ipc_pending_reply("received", header);
707 msg->pending = true;
708 hsw->pending = true;
709 return 1;
710 case IPC_GLB_REPLY_SUCCESS:
711 if (msg->pending) {
712 trace_ipc_pending_reply("completed", header);
713 sst_dsp_inbox_read(hsw->dsp, msg->rx_data,
714 msg->rx_size);
715 hsw->pending = false;
716 } else {
717 /* copy data from the DSP */
718 sst_dsp_outbox_read(hsw->dsp, msg->rx_data,
719 msg->rx_size);
720 }
721 break;
722 /* these will be rare - but useful for debug */
723 case IPC_GLB_REPLY_UNKNOWN_MESSAGE_TYPE:
724 trace_ipc_error("error: unknown message type", header);
725 msg->errno = -EBADMSG;
726 break;
727 case IPC_GLB_REPLY_OUT_OF_RESOURCES:
728 trace_ipc_error("error: out of resources", header);
729 msg->errno = -ENOMEM;
730 break;
731 case IPC_GLB_REPLY_BUSY:
732 trace_ipc_error("error: reply busy", header);
733 msg->errno = -EBUSY;
734 break;
735 case IPC_GLB_REPLY_FAILURE:
736 trace_ipc_error("error: reply failure", header);
737 msg->errno = -EINVAL;
738 break;
739 case IPC_GLB_REPLY_STAGE_UNINITIALIZED:
740 trace_ipc_error("error: stage uninitialized", header);
741 msg->errno = -EINVAL;
742 break;
743 case IPC_GLB_REPLY_NOT_FOUND:
744 trace_ipc_error("error: reply not found", header);
745 msg->errno = -EINVAL;
746 break;
747 case IPC_GLB_REPLY_SOURCE_NOT_STARTED:
748 trace_ipc_error("error: source not started", header);
749 msg->errno = -EINVAL;
750 break;
751 case IPC_GLB_REPLY_INVALID_REQUEST:
752 trace_ipc_error("error: invalid request", header);
753 msg->errno = -EINVAL;
754 break;
755 case IPC_GLB_REPLY_ERROR_INVALID_PARAM:
756 trace_ipc_error("error: invalid parameter", header);
757 msg->errno = -EINVAL;
758 break;
759 default:
760 trace_ipc_error("error: unknown reply", header);
761 msg->errno = -EINVAL;
762 break;
763 }
764
765 /* update any stream states */
766 hsw_stream_update(hsw, msg);
767
768 /* wake up and return the error if we have waiters on this message ? */
769 list_del(&msg->list);
770 tx_msg_reply_complete(hsw, msg);
771
772 return 1;
773}
774
775static int hsw_stream_message(struct sst_hsw *hsw, u32 header)
776{
777 u32 stream_msg, stream_id, stage_type;
778 struct sst_hsw_stream *stream;
779 int handled = 0;
780
781 stream_msg = msg_get_stream_type(header);
782 stream_id = msg_get_stream_id(header);
783 stage_type = msg_get_stage_type(header);
784
785 stream = get_stream_by_id(hsw, stream_id);
786 if (stream == NULL)
787 return handled;
788
789 stream->header = header;
790
791 switch (stream_msg) {
792 case IPC_STR_STAGE_MESSAGE:
793 dev_err(hsw->dev, "error: stage msg not implemented 0x%8.8x\n",
794 header);
795 break;
796 case IPC_STR_NOTIFICATION:
797 schedule_work(&stream->notify_work);
798 break;
799 default:
800 /* handle pending message complete request */
801 handled = hsw_process_reply(hsw, header);
802 break;
803 }
804
805 return handled;
806}
807
808static int hsw_log_message(struct sst_hsw *hsw, u32 header)
809{
810 u32 operation = (header & IPC_LOG_OP_MASK) >> IPC_LOG_OP_SHIFT;
811 struct sst_hsw_log_stream *stream = &hsw->log_stream;
812 int ret = 1;
813
814 if (operation != IPC_DEBUG_REQUEST_LOG_DUMP) {
815 dev_err(hsw->dev,
816 "error: log msg not implemented 0x%8.8x\n", header);
817 return 0;
818 }
819
820 mutex_lock(&stream->rw_mutex);
821 stream->last_pos = stream->curr_pos;
822 sst_dsp_inbox_read(
823 hsw->dsp, &stream->curr_pos, sizeof(stream->curr_pos));
824 mutex_unlock(&stream->rw_mutex);
825
826 schedule_work(&stream->notify_work);
827
828 return ret;
829}
830
831static int hsw_process_notification(struct sst_hsw *hsw)
832{
833 struct sst_dsp *sst = hsw->dsp;
834 u32 type, header;
835 int handled = 1;
836
837 header = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
838 type = msg_get_global_type(header);
839
840 trace_ipc_request("processing -->", header);
841
842 /* FW Ready is a special case */
843 if (!hsw->boot_complete && header & IPC_FW_READY) {
844 hsw_fw_ready(hsw, header);
845 return handled;
846 }
847
848 switch (type) {
849 case IPC_GLB_GET_FW_VERSION:
850 case IPC_GLB_ALLOCATE_STREAM:
851 case IPC_GLB_FREE_STREAM:
852 case IPC_GLB_GET_FW_CAPABILITIES:
853 case IPC_GLB_REQUEST_DUMP:
854 case IPC_GLB_GET_DEVICE_FORMATS:
855 case IPC_GLB_SET_DEVICE_FORMATS:
856 case IPC_GLB_ENTER_DX_STATE:
857 case IPC_GLB_GET_MIXER_STREAM_INFO:
858 case IPC_GLB_MAX_IPC_MESSAGE_TYPE:
859 case IPC_GLB_RESTORE_CONTEXT:
860 case IPC_GLB_SHORT_REPLY:
861 dev_err(hsw->dev, "error: message type %d header 0x%x\n",
862 type, header);
863 break;
864 case IPC_GLB_STREAM_MESSAGE:
865 handled = hsw_stream_message(hsw, header);
866 break;
867 case IPC_GLB_DEBUG_LOG_MESSAGE:
868 handled = hsw_log_message(hsw, header);
869 break;
870 default:
871 dev_err(hsw->dev, "error: unexpected type %d hdr 0x%8.8x\n",
872 type, header);
873 break;
874 }
875
876 return handled;
877}
878
879static irqreturn_t hsw_irq_thread(int irq, void *context)
880{
881 struct sst_dsp *sst = (struct sst_dsp *) context;
882 struct sst_hsw *hsw = sst_dsp_get_thread_context(sst);
883 u32 ipcx, ipcd;
884 int handled;
885 unsigned long flags;
886
887 spin_lock_irqsave(&sst->spinlock, flags);
888
889 ipcx = sst_dsp_ipc_msg_rx(hsw->dsp);
890 ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD);
891
892 /* reply message from DSP */
893 if (ipcx & SST_IPCX_DONE) {
894
895 /* Handle Immediate reply from DSP Core */
896 handled = hsw_process_reply(hsw, ipcx);
897
898 if (handled > 0) {
899 /* clear DONE bit - tell DSP we have completed */
900 sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX,
901 SST_IPCX_DONE, 0);
902
903 /* unmask Done interrupt */
904 sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
905 SST_IMRX_DONE, 0);
906 }
907 }
908
909 /* new message from DSP */
910 if (ipcd & SST_IPCD_BUSY) {
911
912 /* Handle Notification and Delayed reply from DSP Core */
913 handled = hsw_process_notification(hsw);
914
915 /* clear BUSY bit and set DONE bit - accept new messages */
916 if (handled > 0) {
917 sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD,
918 SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
919
920 /* unmask busy interrupt */
921 sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX,
922 SST_IMRX_BUSY, 0);
923 }
924 }
925
926 spin_unlock_irqrestore(&sst->spinlock, flags);
927
928 /* continue to send any remaining messages... */
929 queue_kthread_work(&hsw->kworker, &hsw->kwork);
930
931 return IRQ_HANDLED;
932}
933
934int sst_hsw_fw_get_version(struct sst_hsw *hsw,
935 struct sst_hsw_ipc_fw_version *version)
936{
937 int ret;
938
939 ret = ipc_tx_message_wait(hsw, IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION),
940 NULL, 0, version, sizeof(*version));
941 if (ret < 0)
942 dev_err(hsw->dev, "error: get version failed\n");
943
944 return ret;
945}
946
947/* Mixer Controls */
948int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
949 u32 stage_id, u32 channel)
950{
951 int ret;
952
953 ret = sst_hsw_stream_get_volume(hsw, stream, stage_id, channel,
954 &stream->mute_volume[channel]);
955 if (ret < 0)
956 return ret;
957
958 ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, 0);
959 if (ret < 0) {
960 dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n",
961 stream->reply.stream_hw_id, channel);
962 return ret;
963 }
964
965 stream->mute[channel] = 1;
966 return 0;
967}
968
969int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
970 u32 stage_id, u32 channel)
971
972{
973 int ret;
974
975 stream->mute[channel] = 0;
976 ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel,
977 stream->mute_volume[channel]);
978 if (ret < 0) {
979 dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n",
980 stream->reply.stream_hw_id, channel);
981 return ret;
982 }
983
984 return 0;
985}
986
987int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
988 u32 stage_id, u32 channel, u32 *volume)
989{
990 if (channel > 1)
991 return -EINVAL;
992
993 sst_dsp_read(hsw->dsp, volume,
994 stream->reply.volume_register_address[channel], sizeof(volume));
995
996 return 0;
997}
998
999int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw,
1000 struct sst_hsw_stream *stream, u64 curve_duration,
1001 enum sst_hsw_volume_curve curve)
1002{
1003 /* curve duration in steps of 100ns */
1004 stream->vol_req.curve_duration = curve_duration;
1005 stream->vol_req.curve_type = curve;
1006
1007 return 0;
1008}
1009
1010/* stream volume */
1011int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
1012 struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume)
1013{
1014 struct sst_hsw_ipc_volume_req *req;
1015 u32 header;
1016 int ret;
1017
1018 trace_ipc_request("set stream volume", stream->reply.stream_hw_id);
1019
1020 if (channel > 1)
1021 return -EINVAL;
1022
1023 if (stream->mute[channel]) {
1024 stream->mute_volume[channel] = volume;
1025 return 0;
1026 }
1027
1028 header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
1029 IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
1030 header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT);
1031 header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT);
1032 header |= (stage_id << IPC_STG_ID_SHIFT);
1033
1034 req = &stream->vol_req;
1035 req->channel = channel;
1036 req->target_volume = volume;
1037
1038 ret = ipc_tx_message_wait(hsw, header, req, sizeof(*req), NULL, 0);
1039 if (ret < 0) {
1040 dev_err(hsw->dev, "error: set stream volume failed\n");
1041 return ret;
1042 }
1043
1044 return 0;
1045}
1046
1047int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel)
1048{
1049 int ret;
1050
1051 ret = sst_hsw_mixer_get_volume(hsw, stage_id, channel,
1052 &hsw->mute_volume[channel]);
1053 if (ret < 0)
1054 return ret;
1055
1056 ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, 0);
1057 if (ret < 0) {
1058 dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n",
1059 channel);
1060 return ret;
1061 }
1062
1063 hsw->mute[channel] = 1;
1064 return 0;
1065}
1066
1067int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel)
1068{
1069 int ret;
1070
1071 ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel,
1072 hsw->mixer_info.volume_register_address[channel]);
1073 if (ret < 0) {
1074 dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n",
1075 channel);
1076 return ret;
1077 }
1078
1079 hsw->mute[channel] = 0;
1080 return 0;
1081}
1082
1083int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
1084 u32 *volume)
1085{
1086 if (channel > 1)
1087 return -EINVAL;
1088
1089 sst_dsp_read(hsw->dsp, volume,
1090 hsw->mixer_info.volume_register_address[channel],
1091 sizeof(*volume));
1092
1093 return 0;
1094}
1095
1096int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw,
1097 u64 curve_duration, enum sst_hsw_volume_curve curve)
1098{
1099 /* curve duration in steps of 100ns */
1100 hsw->curve_duration = curve_duration;
1101 hsw->curve_type = curve;
1102
1103 return 0;
1104}
1105
1106/* global mixer volume */
1107int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
1108 u32 volume)
1109{
1110 struct sst_hsw_ipc_volume_req req;
1111 u32 header;
1112 int ret;
1113
1114 trace_ipc_request("set mixer volume", volume);
1115
1116 /* set both at same time ? */
1117 if (channel == 2) {
1118 if (hsw->mute[0] && hsw->mute[1]) {
1119 hsw->mute_volume[0] = hsw->mute_volume[1] = volume;
1120 return 0;
1121 } else if (hsw->mute[0])
1122 req.channel = 1;
1123 else if (hsw->mute[1])
1124 req.channel = 0;
1125 else
1126 req.channel = 0xffffffff;
1127 } else {
1128 /* set only 1 channel */
1129 if (hsw->mute[channel]) {
1130 hsw->mute_volume[channel] = volume;
1131 return 0;
1132 }
1133 req.channel = channel;
1134 }
1135
1136 header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
1137 IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
1138 header |= (hsw->mixer_info.mixer_hw_id << IPC_STR_ID_SHIFT);
1139 header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT);
1140 header |= (stage_id << IPC_STG_ID_SHIFT);
1141
1142 req.curve_duration = hsw->curve_duration;
1143 req.curve_type = hsw->curve_type;
1144 req.target_volume = volume;
1145
1146 ret = ipc_tx_message_wait(hsw, header, &req, sizeof(req), NULL, 0);
1147 if (ret < 0) {
1148 dev_err(hsw->dev, "error: set mixer volume failed\n");
1149 return ret;
1150 }
1151
1152 return 0;
1153}
1154
1155/* Stream API */
1156struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
1157 u32 (*notify_position)(struct sst_hsw_stream *stream, void *data),
1158 void *data)
1159{
1160 struct sst_hsw_stream *stream;
1161
1162 stream = kzalloc(sizeof(*stream), GFP_KERNEL);
1163 if (stream == NULL)
1164 return NULL;
1165
1166 list_add(&stream->node, &hsw->stream_list);
1167 stream->notify_position = notify_position;
1168 stream->pdata = data;
1169 stream->hsw = hsw;
1170 stream->host_id = id;
1171
1172 /* work to process notification messages */
1173 INIT_WORK(&stream->notify_work, hsw_notification_work);
1174
1175 return stream;
1176}
1177
1178int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
1179{
1180 u32 header;
1181 int ret = 0;
1182
1183 /* dont free DSP streams that are not commited */
1184 if (!stream->commited)
1185 goto out;
1186
1187 trace_ipc_request("stream free", stream->host_id);
1188
1189 stream->free_req.stream_id = stream->reply.stream_hw_id;
1190 header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM);
1191
1192 ret = ipc_tx_message_wait(hsw, header, &stream->free_req,
1193 sizeof(stream->free_req), NULL, 0);
1194 if (ret < 0) {
1195 dev_err(hsw->dev, "error: free stream %d failed\n",
1196 stream->free_req.stream_id);
1197 return -EAGAIN;
1198 }
1199
1200 trace_hsw_stream_free_req(stream, &stream->free_req);
1201
1202out:
1203 list_del(&stream->node);
1204 kfree(stream);
1205
1206 return ret;
1207}
1208
1209int sst_hsw_stream_set_bits(struct sst_hsw *hsw,
1210 struct sst_hsw_stream *stream, enum sst_hsw_bitdepth bits)
1211{
1212 if (stream->commited) {
1213 dev_err(hsw->dev, "error: stream committed for set bits\n");
1214 return -EINVAL;
1215 }
1216
1217 stream->request.format.bitdepth = bits;
1218 return 0;
1219}
1220
1221int sst_hsw_stream_set_channels(struct sst_hsw *hsw,
1222 struct sst_hsw_stream *stream, int channels)
1223{
1224 if (stream->commited) {
1225 dev_err(hsw->dev, "error: stream committed for set channels\n");
1226 return -EINVAL;
1227 }
1228
1229 /* stereo is only supported atm */
1230 if (channels != 2)
1231 return -EINVAL;
1232
1233 stream->request.format.ch_num = channels;
1234 return 0;
1235}
1236
1237int sst_hsw_stream_set_rate(struct sst_hsw *hsw,
1238 struct sst_hsw_stream *stream, int rate)
1239{
1240 if (stream->commited) {
1241 dev_err(hsw->dev, "error: stream committed for set rate\n");
1242 return -EINVAL;
1243 }
1244
1245 stream->request.format.frequency = rate;
1246 return 0;
1247}
1248
1249int sst_hsw_stream_set_map_config(struct sst_hsw *hsw,
1250 struct sst_hsw_stream *stream, u32 map,
1251 enum sst_hsw_channel_config config)
1252{
1253 if (stream->commited) {
1254 dev_err(hsw->dev, "error: stream committed for set map\n");
1255 return -EINVAL;
1256 }
1257
1258 stream->request.format.map = map;
1259 stream->request.format.config = config;
1260 return 0;
1261}
1262
1263int sst_hsw_stream_set_style(struct sst_hsw *hsw,
1264 struct sst_hsw_stream *stream, enum sst_hsw_interleaving style)
1265{
1266 if (stream->commited) {
1267 dev_err(hsw->dev, "error: stream committed for set style\n");
1268 return -EINVAL;
1269 }
1270
1271 stream->request.format.style = style;
1272 return 0;
1273}
1274
1275int sst_hsw_stream_set_valid(struct sst_hsw *hsw,
1276 struct sst_hsw_stream *stream, u32 bits)
1277{
1278 if (stream->commited) {
1279 dev_err(hsw->dev, "error: stream committed for set valid bits\n");
1280 return -EINVAL;
1281 }
1282
1283 stream->request.format.valid_bit = bits;
1284 return 0;
1285}
1286
1287/* Stream Configuration */
1288int sst_hsw_stream_format(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
1289 enum sst_hsw_stream_path_id path_id,
1290 enum sst_hsw_stream_type stream_type,
1291 enum sst_hsw_stream_format format_id)
1292{
1293 if (stream->commited) {
1294 dev_err(hsw->dev, "error: stream committed for set format\n");
1295 return -EINVAL;
1296 }
1297
1298 stream->request.path_id = path_id;
1299 stream->request.stream_type = stream_type;
1300 stream->request.format_id = format_id;
1301
1302 trace_hsw_stream_alloc_request(stream, &stream->request);
1303
1304 return 0;
1305}
1306
1307int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
1308 u32 ring_pt_address, u32 num_pages,
1309 u32 ring_size, u32 ring_offset, u32 ring_first_pfn)
1310{
1311 if (stream->commited) {
1312 dev_err(hsw->dev, "error: stream committed for buffer\n");
1313 return -EINVAL;
1314 }
1315
1316 stream->request.ringinfo.ring_pt_address = ring_pt_address;
1317 stream->request.ringinfo.num_pages = num_pages;
1318 stream->request.ringinfo.ring_size = ring_size;
1319 stream->request.ringinfo.ring_offset = ring_offset;
1320 stream->request.ringinfo.ring_first_pfn = ring_first_pfn;
1321
1322 trace_hsw_stream_buffer(stream);
1323
1324 return 0;
1325}
1326
1327int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
1328 struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id,
1329 u32 entry_point)
1330{
1331 struct sst_hsw_module_map *map = &stream->request.map;
1332
1333 if (stream->commited) {
1334 dev_err(hsw->dev, "error: stream committed for set module\n");
1335 return -EINVAL;
1336 }
1337
1338 /* only support initial module atm */
1339 map->module_entries_count = 1;
1340 map->module_entries[0].module_id = module_id;
1341 map->module_entries[0].entry_point = entry_point;
1342
1343 return 0;
1344}
1345
1346int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
1347 struct sst_hsw_stream *stream, u32 offset, u32 size)
1348{
1349 if (stream->commited) {
1350 dev_err(hsw->dev, "error: stream committed for set pmem\n");
1351 return -EINVAL;
1352 }
1353
1354 stream->request.persistent_mem.offset = offset;
1355 stream->request.persistent_mem.size = size;
1356
1357 return 0;
1358}
1359
1360int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
1361 struct sst_hsw_stream *stream, u32 offset, u32 size)
1362{
1363 if (stream->commited) {
1364 dev_err(hsw->dev, "error: stream committed for set smem\n");
1365 return -EINVAL;
1366 }
1367
1368 stream->request.scratch_mem.offset = offset;
1369 stream->request.scratch_mem.size = size;
1370
1371 return 0;
1372}
1373
1374int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
1375{
1376 struct sst_hsw_ipc_stream_alloc_req *str_req = &stream->request;
1377 struct sst_hsw_ipc_stream_alloc_reply *reply = &stream->reply;
1378 u32 header;
1379 int ret;
1380
1381 trace_ipc_request("stream alloc", stream->host_id);
1382
1383 header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM);
1384
1385 ret = ipc_tx_message_wait(hsw, header, str_req, sizeof(*str_req),
1386 reply, sizeof(*reply));
1387 if (ret < 0) {
1388 dev_err(hsw->dev, "error: stream commit failed\n");
1389 return ret;
1390 }
1391
1392 stream->commited = 1;
1393 trace_hsw_stream_alloc_reply(stream);
1394
1395 return 0;
1396}
1397
1398/* Stream Information - these calls could be inline but we want the IPC
1399 ABI to be opaque to client PCM drivers to cope with any future ABI changes */
1400int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw,
1401 struct sst_hsw_stream *stream)
1402{
1403 return stream->reply.stream_hw_id;
1404}
1405
1406int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw,
1407 struct sst_hsw_stream *stream)
1408{
1409 return stream->reply.mixer_hw_id;
1410}
1411
1412u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw,
1413 struct sst_hsw_stream *stream)
1414{
1415 return stream->reply.read_position_register_address;
1416}
1417
1418u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw,
1419 struct sst_hsw_stream *stream)
1420{
1421 return stream->reply.presentation_position_register_address;
1422}
1423
1424u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw,
1425 struct sst_hsw_stream *stream, u32 channel)
1426{
1427 if (channel >= 2)
1428 return 0;
1429
1430 return stream->reply.peak_meter_register_address[channel];
1431}
1432
1433u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw,
1434 struct sst_hsw_stream *stream, u32 channel)
1435{
1436 if (channel >= 2)
1437 return 0;
1438
1439 return stream->reply.volume_register_address[channel];
1440}
1441
1442int sst_hsw_mixer_get_info(struct sst_hsw *hsw)
1443{
1444 struct sst_hsw_ipc_stream_info_reply *reply;
1445 u32 header;
1446 int ret;
1447
1448 reply = &hsw->mixer_info;
1449 header = IPC_GLB_TYPE(IPC_GLB_GET_MIXER_STREAM_INFO);
1450
1451 trace_ipc_request("get global mixer info", 0);
1452
1453 ret = ipc_tx_message_wait(hsw, header, NULL, 0, reply, sizeof(*reply));
1454 if (ret < 0) {
1455 dev_err(hsw->dev, "error: get stream info failed\n");
1456 return ret;
1457 }
1458
1459 trace_hsw_mixer_info_reply(reply);
1460
1461 return 0;
1462}
1463
1464/* Send stream command */
1465static int sst_hsw_stream_operations(struct sst_hsw *hsw, int type,
1466 int stream_id, int wait)
1467{
1468 u32 header;
1469
1470 header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | IPC_STR_TYPE(type);
1471 header |= (stream_id << IPC_STR_ID_SHIFT);
1472
1473 if (wait)
1474 return ipc_tx_message_wait(hsw, header, NULL, 0, NULL, 0);
1475 else
1476 return ipc_tx_message_nowait(hsw, header, NULL, 0);
1477}
1478
1479/* Stream ALSA trigger operations */
1480int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
1481 int wait)
1482{
1483 int ret;
1484
1485 trace_ipc_request("stream pause", stream->reply.stream_hw_id);
1486
1487 ret = sst_hsw_stream_operations(hsw, IPC_STR_PAUSE,
1488 stream->reply.stream_hw_id, wait);
1489 if (ret < 0)
1490 dev_err(hsw->dev, "error: failed to pause stream %d\n",
1491 stream->reply.stream_hw_id);
1492
1493 return ret;
1494}
1495
1496int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
1497 int wait)
1498{
1499 int ret;
1500
1501 trace_ipc_request("stream resume", stream->reply.stream_hw_id);
1502
1503 ret = sst_hsw_stream_operations(hsw, IPC_STR_RESUME,
1504 stream->reply.stream_hw_id, wait);
1505 if (ret < 0)
1506 dev_err(hsw->dev, "error: failed to resume stream %d\n",
1507 stream->reply.stream_hw_id);
1508
1509 return ret;
1510}
1511
1512int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
1513{
1514 int ret, tries = 10;
1515
1516 /* dont reset streams that are not commited */
1517 if (!stream->commited)
1518 return 0;
1519
1520 /* wait for pause to complete before we reset the stream */
1521 while (stream->running && tries--)
1522 msleep(1);
1523 if (!tries) {
1524 dev_err(hsw->dev, "error: reset stream %d still running\n",
1525 stream->reply.stream_hw_id);
1526 return -EINVAL;
1527 }
1528
1529 trace_ipc_request("stream reset", stream->reply.stream_hw_id);
1530
1531 ret = sst_hsw_stream_operations(hsw, IPC_STR_RESET,
1532 stream->reply.stream_hw_id, 1);
1533 if (ret < 0)
1534 dev_err(hsw->dev, "error: failed to reset stream %d\n",
1535 stream->reply.stream_hw_id);
1536 return ret;
1537}
1538
1539/* Stream pointer positions */
1540int sst_hsw_get_dsp_position(struct sst_hsw *hsw,
1541 struct sst_hsw_stream *stream)
1542{
1543 return stream->rpos.position;
1544}
1545
1546int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
1547 struct sst_hsw_stream *stream, u32 stage_id, u32 position)
1548{
1549 u32 header;
1550 int ret;
1551
1552 trace_stream_write_position(stream->reply.stream_hw_id, position);
1553
1554 header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
1555 IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
1556 header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT);
1557 header |= (IPC_STG_SET_WRITE_POSITION << IPC_STG_TYPE_SHIFT);
1558 header |= (stage_id << IPC_STG_ID_SHIFT);
1559 stream->wpos.position = position;
1560
1561 ret = ipc_tx_message_nowait(hsw, header, &stream->wpos,
1562 sizeof(stream->wpos));
1563 if (ret < 0)
1564 dev_err(hsw->dev, "error: stream %d set position %d failed\n",
1565 stream->reply.stream_hw_id, position);
1566
1567 return ret;
1568}
1569
1570/* physical BE config */
1571int sst_hsw_device_set_config(struct sst_hsw *hsw,
1572 enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk,
1573 enum sst_hsw_device_mode mode, u32 clock_divider)
1574{
1575 struct sst_hsw_ipc_device_config_req config;
1576 u32 header;
1577 int ret;
1578
1579 trace_ipc_request("set device config", dev);
1580
1581 config.ssp_interface = dev;
1582 config.clock_frequency = mclk;
1583 config.mode = mode;
1584 config.clock_divider = clock_divider;
1585
1586 trace_hsw_device_config_req(&config);
1587
1588 header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS);
1589
1590 ret = ipc_tx_message_wait(hsw, header, &config, sizeof(config),
1591 NULL, 0);
1592 if (ret < 0)
1593 dev_err(hsw->dev, "error: set device formats failed\n");
1594
1595 return ret;
1596}
1597EXPORT_SYMBOL_GPL(sst_hsw_device_set_config);
1598
1599/* DX Config */
1600int sst_hsw_dx_set_state(struct sst_hsw *hsw,
1601 enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx)
1602{
1603 u32 header, state_;
1604 int ret;
1605
1606 header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE);
1607 state_ = state;
1608
1609 trace_ipc_request("PM enter Dx state", state);
1610
1611 ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_),
1612 dx, sizeof(dx));
1613 if (ret < 0) {
1614 dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state);
1615 return ret;
1616 }
1617
1618 dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n",
1619 dx->entries_no, state);
1620
1621 memcpy(&hsw->dx, dx, sizeof(*dx));
1622 return 0;
1623}
1624
1625/* Used to save state into hsw->dx_reply */
1626int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item,
1627 u32 *offset, u32 *size, u32 *source)
1628{
1629 struct sst_hsw_ipc_dx_memory_item *dx_mem;
1630 struct sst_hsw_ipc_dx_reply *dx_reply;
1631 int entry_no;
1632
1633 dx_reply = &hsw->dx;
1634 entry_no = dx_reply->entries_no;
1635
1636 trace_ipc_request("PM get Dx state", entry_no);
1637
1638 if (item >= entry_no)
1639 return -EINVAL;
1640
1641 dx_mem = &dx_reply->mem_info[item];
1642 *offset = dx_mem->offset;
1643 *size = dx_mem->size;
1644 *source = dx_mem->source;
1645
1646 return 0;
1647}
1648
1649static int msg_empty_list_init(struct sst_hsw *hsw)
1650{
1651 int i;
1652
1653 hsw->msg = kzalloc(sizeof(struct ipc_message) *
1654 IPC_EMPTY_LIST_SIZE, GFP_KERNEL);
1655 if (hsw->msg == NULL)
1656 return -ENOMEM;
1657
1658 for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) {
1659 init_waitqueue_head(&hsw->msg[i].waitq);
1660 list_add(&hsw->msg[i].list, &hsw->empty_list);
1661 }
1662
1663 return 0;
1664}
1665
1666void sst_hsw_set_scratch_module(struct sst_hsw *hsw,
1667 struct sst_module *scratch)
1668{
1669 hsw->scratch = scratch;
1670}
1671
1672struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw)
1673{
1674 return hsw->dsp;
1675}
1676
1677static struct sst_dsp_device hsw_dev = {
1678 .thread = hsw_irq_thread,
1679 .ops = &haswell_ops,
1680};
1681
1682int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
1683{
1684 struct sst_hsw_ipc_fw_version version;
1685 struct sst_hsw *hsw;
1686 struct sst_fw *hsw_sst_fw;
1687 int ret;
1688
1689 dev_dbg(dev, "initialising Audio DSP IPC\n");
1690
1691 hsw = devm_kzalloc(dev, sizeof(*hsw), GFP_KERNEL);
1692 if (hsw == NULL)
1693 return -ENOMEM;
1694
1695 hsw->dev = dev;
1696 INIT_LIST_HEAD(&hsw->stream_list);
1697 INIT_LIST_HEAD(&hsw->tx_list);
1698 INIT_LIST_HEAD(&hsw->rx_list);
1699 INIT_LIST_HEAD(&hsw->empty_list);
1700 init_waitqueue_head(&hsw->boot_wait);
1701 init_waitqueue_head(&hsw->wait_txq);
1702
1703 ret = msg_empty_list_init(hsw);
1704 if (ret < 0)
1705 goto list_err;
1706
1707 /* start the IPC message thread */
1708 init_kthread_worker(&hsw->kworker);
1709 hsw->tx_thread = kthread_run(kthread_worker_fn,
1710 &hsw->kworker,
1711 dev_name(hsw->dev));
1712 if (IS_ERR(hsw->tx_thread)) {
1713 ret = PTR_ERR(hsw->tx_thread);
1714 dev_err(hsw->dev, "error: failed to create message TX task\n");
1715 goto list_err;
1716 }
1717 init_kthread_work(&hsw->kwork, ipc_tx_msgs);
1718
1719 hsw_dev.thread_context = hsw;
1720
1721 /* init SST shim */
1722 hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata);
1723 if (hsw->dsp == NULL) {
1724 ret = -ENODEV;
1725 goto list_err;
1726 }
1727
1728 /* keep the DSP in reset state for base FW loading */
1729 sst_dsp_reset(hsw->dsp);
1730
1731 hsw_sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw);
1732
1733 if (hsw_sst_fw == NULL) {
1734 ret = -ENODEV;
1735 dev_err(dev, "error: failed to load firmware\n");
1736 goto fw_err;
1737 }
1738
1739 /* wait for DSP boot completion */
1740 sst_dsp_boot(hsw->dsp);
1741 ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,
1742 msecs_to_jiffies(IPC_BOOT_MSECS));
1743 if (ret == 0) {
1744 ret = -EIO;
1745 dev_err(hsw->dev, "error: ADSP boot timeout\n");
1746 goto boot_err;
1747 }
1748
1749 /* get the FW version */
1750 sst_hsw_fw_get_version(hsw, &version);
1751 dev_info(hsw->dev, "FW loaded: type %d - version: %d.%d build %d\n",
1752 version.type, version.major, version.minor, version.build);
1753
1754 /* get the globalmixer */
1755 ret = sst_hsw_mixer_get_info(hsw);
1756 if (ret < 0) {
1757 dev_err(hsw->dev, "error: failed to get stream info\n");
1758 goto boot_err;
1759 }
1760
1761 pdata->dsp = hsw;
1762 return 0;
1763
1764boot_err:
1765 sst_dsp_reset(hsw->dsp);
1766 sst_fw_free(hsw_sst_fw);
1767fw_err:
1768 sst_dsp_free(hsw->dsp);
1769 kfree(hsw->msg);
1770list_err:
1771 return ret;
1772}
1773EXPORT_SYMBOL_GPL(sst_hsw_dsp_init);
1774
1775void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata)
1776{
1777 struct sst_hsw *hsw = pdata->dsp;
1778
1779 sst_dsp_reset(hsw->dsp);
1780 sst_fw_free_all(hsw->dsp);
1781 sst_dsp_free(hsw->dsp);
1782 kfree(hsw->scratch);
1783 kfree(hsw->msg);
1784}
1785EXPORT_SYMBOL_GPL(sst_hsw_dsp_free);
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h
new file mode 100644
index 000000000000..d517929ccc38
--- /dev/null
+++ b/sound/soc/intel/sst-haswell-ipc.h
@@ -0,0 +1,488 @@
1/*
2 * Intel SST Haswell/Broadwell IPC Support
3 *
4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#ifndef __SST_HASWELL_IPC_H
18#define __SST_HASWELL_IPC_H
19
20#include <linux/types.h>
21#include <linux/kernel.h>
22#include <linux/platform_device.h>
23
24#define SST_HSW_NO_CHANNELS 2
25#define SST_HSW_MAX_DX_REGIONS 14
26
27#define SST_HSW_FW_LOG_CONFIG_DWORDS 12
28#define SST_HSW_GLOBAL_LOG 15
29
30/**
31 * Upfront defined maximum message size that is
32 * expected by the in/out communication pipes in FW.
33 */
34#define SST_HSW_IPC_MAX_PAYLOAD_SIZE 400
35#define SST_HSW_MAX_INFO_SIZE 64
36#define SST_HSW_BUILD_HASH_LENGTH 40
37
38struct sst_hsw;
39struct sst_hsw_stream;
40struct sst_hsw_log_stream;
41struct sst_pdata;
42struct sst_module;
43extern struct sst_ops haswell_ops;
44
45/* Stream Allocate Path ID */
46enum sst_hsw_stream_path_id {
47 SST_HSW_STREAM_PATH_SSP0_OUT = 0,
48 SST_HSW_STREAM_PATH_SSP0_IN = 1,
49 SST_HSW_STREAM_PATH_MAX_PATH_ID = 2,
50};
51
52/* Stream Allocate Stream Type */
53enum sst_hsw_stream_type {
54 SST_HSW_STREAM_TYPE_RENDER = 0,
55 SST_HSW_STREAM_TYPE_SYSTEM = 1,
56 SST_HSW_STREAM_TYPE_CAPTURE = 2,
57 SST_HSW_STREAM_TYPE_LOOPBACK = 3,
58 SST_HSW_STREAM_TYPE_MAX_STREAM_TYPE = 4,
59};
60
61/* Stream Allocate Stream Format */
62enum sst_hsw_stream_format {
63 SST_HSW_STREAM_FORMAT_PCM_FORMAT = 0,
64 SST_HSW_STREAM_FORMAT_MP3_FORMAT = 1,
65 SST_HSW_STREAM_FORMAT_AAC_FORMAT = 2,
66 SST_HSW_STREAM_FORMAT_MAX_FORMAT_ID = 3,
67};
68
69/* Device ID */
70enum sst_hsw_device_id {
71 SST_HSW_DEVICE_SSP_0 = 0,
72 SST_HSW_DEVICE_SSP_1 = 1,
73};
74
75/* Device Master Clock Frequency */
76enum sst_hsw_device_mclk {
77 SST_HSW_DEVICE_MCLK_OFF = 0,
78 SST_HSW_DEVICE_MCLK_FREQ_6_MHZ = 1,
79 SST_HSW_DEVICE_MCLK_FREQ_12_MHZ = 2,
80 SST_HSW_DEVICE_MCLK_FREQ_24_MHZ = 3,
81};
82
83/* Device Clock Master */
84enum sst_hsw_device_mode {
85 SST_HSW_DEVICE_CLOCK_SLAVE = 0,
86 SST_HSW_DEVICE_CLOCK_MASTER = 1,
87};
88
89/* DX Power State */
90enum sst_hsw_dx_state {
91 SST_HSW_DX_STATE_D0 = 0,
92 SST_HSW_DX_STATE_D1 = 1,
93 SST_HSW_DX_STATE_D3 = 3,
94 SST_HSW_DX_STATE_MAX = 3,
95};
96
97/* Audio stream stage IDs */
98enum sst_hsw_fx_stage_id {
99 SST_HSW_STAGE_ID_WAVES = 0,
100 SST_HSW_STAGE_ID_DTS = 1,
101 SST_HSW_STAGE_ID_DOLBY = 2,
102 SST_HSW_STAGE_ID_BOOST = 3,
103 SST_HSW_STAGE_ID_MAX_FX_ID
104};
105
106/* DX State Type */
107enum sst_hsw_dx_type {
108 SST_HSW_DX_TYPE_FW_IMAGE = 0,
109 SST_HSW_DX_TYPE_MEMORY_DUMP = 1
110};
111
112/* Volume Curve Type*/
113enum sst_hsw_volume_curve {
114 SST_HSW_VOLUME_CURVE_NONE = 0,
115 SST_HSW_VOLUME_CURVE_FADE = 1
116};
117
118/* Sample ordering */
119enum sst_hsw_interleaving {
120 SST_HSW_INTERLEAVING_PER_CHANNEL = 0,
121 SST_HSW_INTERLEAVING_PER_SAMPLE = 1,
122};
123
124/* Channel indices */
125enum sst_hsw_channel_index {
126 SST_HSW_CHANNEL_LEFT = 0,
127 SST_HSW_CHANNEL_CENTER = 1,
128 SST_HSW_CHANNEL_RIGHT = 2,
129 SST_HSW_CHANNEL_LEFT_SURROUND = 3,
130 SST_HSW_CHANNEL_CENTER_SURROUND = 3,
131 SST_HSW_CHANNEL_RIGHT_SURROUND = 4,
132 SST_HSW_CHANNEL_LFE = 7,
133 SST_HSW_CHANNEL_INVALID = 0xF,
134};
135
136/* List of supported channel maps. */
137enum sst_hsw_channel_config {
138 SST_HSW_CHANNEL_CONFIG_MONO = 0, /* mono only. */
139 SST_HSW_CHANNEL_CONFIG_STEREO = 1, /* L & R. */
140 SST_HSW_CHANNEL_CONFIG_2_POINT_1 = 2, /* L, R & LFE; PCM only. */
141 SST_HSW_CHANNEL_CONFIG_3_POINT_0 = 3, /* L, C & R; MP3 & AAC only. */
142 SST_HSW_CHANNEL_CONFIG_3_POINT_1 = 4, /* L, C, R & LFE; PCM only. */
143 SST_HSW_CHANNEL_CONFIG_QUATRO = 5, /* L, R, Ls & Rs; PCM only. */
144 SST_HSW_CHANNEL_CONFIG_4_POINT_0 = 6, /* L, C, R & Cs; MP3 & AAC only. */
145 SST_HSW_CHANNEL_CONFIG_5_POINT_0 = 7, /* L, C, R, Ls & Rs. */
146 SST_HSW_CHANNEL_CONFIG_5_POINT_1 = 8, /* L, C, R, Ls, Rs & LFE. */
147 SST_HSW_CHANNEL_CONFIG_DUAL_MONO = 9, /* One channel replicated in two. */
148 SST_HSW_CHANNEL_CONFIG_INVALID,
149};
150
151/* List of supported bit depths. */
152enum sst_hsw_bitdepth {
153 SST_HSW_DEPTH_8BIT = 8,
154 SST_HSW_DEPTH_16BIT = 16,
155 SST_HSW_DEPTH_24BIT = 24, /* Default. */
156 SST_HSW_DEPTH_32BIT = 32,
157 SST_HSW_DEPTH_INVALID = 33,
158};
159
160enum sst_hsw_module_id {
161 SST_HSW_MODULE_BASE_FW = 0x0,
162 SST_HSW_MODULE_MP3 = 0x1,
163 SST_HSW_MODULE_AAC_5_1 = 0x2,
164 SST_HSW_MODULE_AAC_2_0 = 0x3,
165 SST_HSW_MODULE_SRC = 0x4,
166 SST_HSW_MODULE_WAVES = 0x5,
167 SST_HSW_MODULE_DOLBY = 0x6,
168 SST_HSW_MODULE_BOOST = 0x7,
169 SST_HSW_MODULE_LPAL = 0x8,
170 SST_HSW_MODULE_DTS = 0x9,
171 SST_HSW_MODULE_PCM_CAPTURE = 0xA,
172 SST_HSW_MODULE_PCM_SYSTEM = 0xB,
173 SST_HSW_MODULE_PCM_REFERENCE = 0xC,
174 SST_HSW_MODULE_PCM = 0xD,
175 SST_HSW_MODULE_BLUETOOTH_RENDER_MODULE = 0xE,
176 SST_HSW_MODULE_BLUETOOTH_CAPTURE_MODULE = 0xF,
177 SST_HSW_MAX_MODULE_ID,
178};
179
180enum sst_hsw_performance_action {
181 SST_HSW_PERF_START = 0,
182 SST_HSW_PERF_STOP = 1,
183};
184
185/* SST firmware module info */
186struct sst_hsw_module_info {
187 u8 name[SST_HSW_MAX_INFO_SIZE];
188 u8 version[SST_HSW_MAX_INFO_SIZE];
189} __attribute__((packed));
190
191/* Module entry point */
192struct sst_hsw_module_entry {
193 enum sst_hsw_module_id module_id;
194 u32 entry_point;
195} __attribute__((packed));
196
197/* Module map - alignement matches DSP */
198struct sst_hsw_module_map {
199 u8 module_entries_count;
200 struct sst_hsw_module_entry module_entries[1];
201} __attribute__((packed));
202
203struct sst_hsw_memory_info {
204 u32 offset;
205 u32 size;
206} __attribute__((packed));
207
208struct sst_hsw_fx_enable {
209 struct sst_hsw_module_map module_map;
210 struct sst_hsw_memory_info persistent_mem;
211} __attribute__((packed));
212
213struct sst_hsw_get_fx_param {
214 u32 parameter_id;
215 u32 param_size;
216} __attribute__((packed));
217
218struct sst_hsw_perf_action {
219 u32 action;
220} __attribute__((packed));
221
222struct sst_hsw_perf_data {
223 u64 timestamp;
224 u64 cycles;
225 u64 datatime;
226} __attribute__((packed));
227
228/* FW version */
229struct sst_hsw_ipc_fw_version {
230 u8 build;
231 u8 minor;
232 u8 major;
233 u8 type;
234 u8 fw_build_hash[SST_HSW_BUILD_HASH_LENGTH];
235 u32 fw_log_providers_hash;
236} __attribute__((packed));
237
238/* Stream ring info */
239struct sst_hsw_ipc_stream_ring {
240 u32 ring_pt_address;
241 u32 num_pages;
242 u32 ring_size;
243 u32 ring_offset;
244 u32 ring_first_pfn;
245} __attribute__((packed));
246
247/* Debug Dump Log Enable Request */
248struct sst_hsw_ipc_debug_log_enable_req {
249 struct sst_hsw_ipc_stream_ring ringinfo;
250 u32 config[SST_HSW_FW_LOG_CONFIG_DWORDS];
251} __attribute__((packed));
252
253/* Debug Dump Log Reply */
254struct sst_hsw_ipc_debug_log_reply {
255 u32 log_buffer_begining;
256 u32 log_buffer_size;
257} __attribute__((packed));
258
259/* Stream glitch position */
260struct sst_hsw_ipc_stream_glitch_position {
261 u32 glitch_type;
262 u32 present_pos;
263 u32 write_pos;
264} __attribute__((packed));
265
266/* Stream get position */
267struct sst_hsw_ipc_stream_get_position {
268 u32 position;
269 u32 fw_cycle_count;
270} __attribute__((packed));
271
272/* Stream set position */
273struct sst_hsw_ipc_stream_set_position {
274 u32 position;
275 u32 end_of_buffer;
276} __attribute__((packed));
277
278/* Stream Free Request */
279struct sst_hsw_ipc_stream_free_req {
280 u8 stream_id;
281 u8 reserved[3];
282} __attribute__((packed));
283
284/* Set Volume Request */
285struct sst_hsw_ipc_volume_req {
286 u32 channel;
287 u32 target_volume;
288 u64 curve_duration;
289 u32 curve_type;
290} __attribute__((packed));
291
292/* Device Configuration Request */
293struct sst_hsw_ipc_device_config_req {
294 u32 ssp_interface;
295 u32 clock_frequency;
296 u32 mode;
297 u16 clock_divider;
298 u16 reserved;
299} __attribute__((packed));
300
301/* Audio Data formats */
302struct sst_hsw_audio_data_format_ipc {
303 u32 frequency;
304 u32 bitdepth;
305 u32 map;
306 u32 config;
307 u32 style;
308 u8 ch_num;
309 u8 valid_bit;
310 u8 reserved[2];
311} __attribute__((packed));
312
313/* Stream Allocate Request */
314struct sst_hsw_ipc_stream_alloc_req {
315 u8 path_id;
316 u8 stream_type;
317 u8 format_id;
318 u8 reserved;
319 struct sst_hsw_audio_data_format_ipc format;
320 struct sst_hsw_ipc_stream_ring ringinfo;
321 struct sst_hsw_module_map map;
322 struct sst_hsw_memory_info persistent_mem;
323 struct sst_hsw_memory_info scratch_mem;
324 u32 number_of_notifications;
325} __attribute__((packed));
326
327/* Stream Allocate Reply */
328struct sst_hsw_ipc_stream_alloc_reply {
329 u32 stream_hw_id;
330 u32 mixer_hw_id; // returns rate ????
331 u32 read_position_register_address;
332 u32 presentation_position_register_address;
333 u32 peak_meter_register_address[SST_HSW_NO_CHANNELS];
334 u32 volume_register_address[SST_HSW_NO_CHANNELS];
335} __attribute__((packed));
336
337/* Get Mixer Stream Info */
338struct sst_hsw_ipc_stream_info_reply {
339 u32 mixer_hw_id;
340 u32 peak_meter_register_address[SST_HSW_NO_CHANNELS];
341 u32 volume_register_address[SST_HSW_NO_CHANNELS];
342} __attribute__((packed));
343
344/* DX State Request */
345struct sst_hsw_ipc_dx_req {
346 u8 state;
347 u8 reserved[3];
348} __attribute__((packed));
349
350/* DX State Reply Memory Info Item */
351struct sst_hsw_ipc_dx_memory_item {
352 u32 offset;
353 u32 size;
354 u32 source;
355} __attribute__((packed));
356
357/* DX State Reply */
358struct sst_hsw_ipc_dx_reply {
359 u32 entries_no;
360 struct sst_hsw_ipc_dx_memory_item mem_info[SST_HSW_MAX_DX_REGIONS];
361} __attribute__((packed));
362
363struct sst_hsw_ipc_fw_version;
364
365/* SST Init & Free */
366struct sst_hsw *sst_hsw_new(struct device *dev, const u8 *fw, size_t fw_length,
367 u32 fw_offset);
368void sst_hsw_free(struct sst_hsw *hsw);
369int sst_hsw_fw_get_version(struct sst_hsw *hsw,
370 struct sst_hsw_ipc_fw_version *version);
371u32 create_channel_map(enum sst_hsw_channel_config config);
372
373/* Stream Mixer Controls - */
374int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
375 u32 stage_id, u32 channel);
376int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
377 u32 stage_id, u32 channel);
378
379int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
380 struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume);
381int sst_hsw_stream_get_volume(struct sst_hsw *hsw,
382 struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 *volume);
383
384int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw,
385 struct sst_hsw_stream *stream, u64 curve_duration,
386 enum sst_hsw_volume_curve curve);
387
388/* Global Mixer Controls - */
389int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel);
390int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel);
391
392int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
393 u32 volume);
394int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
395 u32 *volume);
396
397int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw,
398 u64 curve_duration, enum sst_hsw_volume_curve curve);
399
400/* Stream API */
401struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
402 u32 (*get_write_position)(struct sst_hsw_stream *stream, void *data),
403 void *data);
404
405int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
406
407/* Stream Configuration */
408int sst_hsw_stream_format(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
409 enum sst_hsw_stream_path_id path_id,
410 enum sst_hsw_stream_type stream_type,
411 enum sst_hsw_stream_format format_id);
412
413int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
414 u32 ring_pt_address, u32 num_pages,
415 u32 ring_size, u32 ring_offset, u32 ring_first_pfn);
416
417int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
418
419int sst_hsw_stream_set_valid(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
420 u32 bits);
421int sst_hsw_stream_set_rate(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
422 int rate);
423int sst_hsw_stream_set_bits(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
424 enum sst_hsw_bitdepth bits);
425int sst_hsw_stream_set_channels(struct sst_hsw *hsw,
426 struct sst_hsw_stream *stream, int channels);
427int sst_hsw_stream_set_map_config(struct sst_hsw *hsw,
428 struct sst_hsw_stream *stream, u32 map,
429 enum sst_hsw_channel_config config);
430int sst_hsw_stream_set_style(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
431 enum sst_hsw_interleaving style);
432int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
433 struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id,
434 u32 entry_point);
435int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
436 struct sst_hsw_stream *stream, u32 offset, u32 size);
437int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
438 struct sst_hsw_stream *stream, u32 offset, u32 size);
439int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw,
440 struct sst_hsw_stream *stream);
441int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw,
442 struct sst_hsw_stream *stream);
443u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw,
444 struct sst_hsw_stream *stream);
445u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw,
446 struct sst_hsw_stream *stream);
447u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw,
448 struct sst_hsw_stream *stream, u32 channel);
449u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw,
450 struct sst_hsw_stream *stream, u32 channel);
451int sst_hsw_mixer_get_info(struct sst_hsw *hsw);
452
453/* Stream ALSA trigger operations */
454int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
455 int wait);
456int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
457 int wait);
458int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream);
459
460/* Stream pointer positions */
461int sst_hsw_stream_get_read_pos(struct sst_hsw *hsw,
462 struct sst_hsw_stream *stream, u32 *position);
463int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw,
464 struct sst_hsw_stream *stream, u32 *position);
465int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
466 struct sst_hsw_stream *stream, u32 stage_id, u32 position);
467int sst_hsw_get_dsp_position(struct sst_hsw *hsw,
468 struct sst_hsw_stream *stream);
469
470/* HW port config */
471int sst_hsw_device_set_config(struct sst_hsw *hsw,
472 enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk,
473 enum sst_hsw_device_mode mode, u32 clock_divider);
474
475/* DX Config */
476int sst_hsw_dx_set_state(struct sst_hsw *hsw,
477 enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx);
478int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item,
479 u32 *offset, u32 *size, u32 *source);
480
481/* init */
482int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata);
483void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata);
484struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw);
485void sst_hsw_set_scratch_module(struct sst_hsw *hsw,
486 struct sst_module *scratch);
487
488#endif
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
new file mode 100644
index 000000000000..0a32dd13a23d
--- /dev/null
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -0,0 +1,872 @@
1/*
2 * Intel SST Haswell/Broadwell PCM Support
3 *
4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/dma-mapping.h>
19#include <linux/slab.h>
20#include <linux/module.h>
21#include <linux/delay.h>
22#include <asm/page.h>
23#include <asm/pgtable.h>
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/dmaengine_pcm.h>
28#include <sound/soc.h>
29#include <sound/tlv.h>
30#include <sound/compress_driver.h>
31
32#include "sst-haswell-ipc.h"
33#include "sst-dsp-priv.h"
34#include "sst-dsp.h"
35
36#define HSW_PCM_COUNT 6
37#define HSW_VOLUME_MAX 0x7FFFFFFF /* 0dB */
38
39/* simple volume table */
40static const u32 volume_map[] = {
41 HSW_VOLUME_MAX >> 30,
42 HSW_VOLUME_MAX >> 29,
43 HSW_VOLUME_MAX >> 28,
44 HSW_VOLUME_MAX >> 27,
45 HSW_VOLUME_MAX >> 26,
46 HSW_VOLUME_MAX >> 25,
47 HSW_VOLUME_MAX >> 24,
48 HSW_VOLUME_MAX >> 23,
49 HSW_VOLUME_MAX >> 22,
50 HSW_VOLUME_MAX >> 21,
51 HSW_VOLUME_MAX >> 20,
52 HSW_VOLUME_MAX >> 19,
53 HSW_VOLUME_MAX >> 18,
54 HSW_VOLUME_MAX >> 17,
55 HSW_VOLUME_MAX >> 16,
56 HSW_VOLUME_MAX >> 15,
57 HSW_VOLUME_MAX >> 14,
58 HSW_VOLUME_MAX >> 13,
59 HSW_VOLUME_MAX >> 12,
60 HSW_VOLUME_MAX >> 11,
61 HSW_VOLUME_MAX >> 10,
62 HSW_VOLUME_MAX >> 9,
63 HSW_VOLUME_MAX >> 8,
64 HSW_VOLUME_MAX >> 7,
65 HSW_VOLUME_MAX >> 6,
66 HSW_VOLUME_MAX >> 5,
67 HSW_VOLUME_MAX >> 4,
68 HSW_VOLUME_MAX >> 3,
69 HSW_VOLUME_MAX >> 2,
70 HSW_VOLUME_MAX >> 1,
71 HSW_VOLUME_MAX >> 0,
72};
73
74#define HSW_PCM_PERIODS_MAX 64
75#define HSW_PCM_PERIODS_MIN 2
76
77static const struct snd_pcm_hardware hsw_pcm_hardware = {
78 .info = SNDRV_PCM_INFO_MMAP |
79 SNDRV_PCM_INFO_MMAP_VALID |
80 SNDRV_PCM_INFO_INTERLEAVED |
81 SNDRV_PCM_INFO_PAUSE |
82 SNDRV_PCM_INFO_RESUME |
83 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
84 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE |
85 SNDRV_PCM_FMTBIT_S32_LE,
86 .period_bytes_min = PAGE_SIZE,
87 .period_bytes_max = (HSW_PCM_PERIODS_MAX / HSW_PCM_PERIODS_MIN) * PAGE_SIZE,
88 .periods_min = HSW_PCM_PERIODS_MIN,
89 .periods_max = HSW_PCM_PERIODS_MAX,
90 .buffer_bytes_max = HSW_PCM_PERIODS_MAX * PAGE_SIZE,
91};
92
93/* private data for each PCM DSP stream */
94struct hsw_pcm_data {
95 int dai_id;
96 struct sst_hsw_stream *stream;
97 u32 volume[2];
98 struct snd_pcm_substream *substream;
99 struct snd_compr_stream *cstream;
100 unsigned int wpos;
101 struct mutex mutex;
102};
103
104/* private data for the driver */
105struct hsw_priv_data {
106 /* runtime DSP */
107 struct sst_hsw *hsw;
108
109 /* page tables */
110 unsigned char *pcm_pg[HSW_PCM_COUNT][2];
111
112 /* DAI data */
113 struct hsw_pcm_data pcm[HSW_PCM_COUNT];
114};
115
116static inline u32 hsw_mixer_to_ipc(unsigned int value)
117{
118 if (value >= ARRAY_SIZE(volume_map))
119 return volume_map[0];
120 else
121 return volume_map[value];
122}
123
124static inline unsigned int hsw_ipc_to_mixer(u32 value)
125{
126 int i;
127
128 for (i = 0; i < ARRAY_SIZE(volume_map); i++) {
129 if (volume_map[i] >= value)
130 return i;
131 }
132
133 return i - 1;
134}
135
136static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
137 struct snd_ctl_elem_value *ucontrol)
138{
139 struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
140 struct soc_mixer_control *mc =
141 (struct soc_mixer_control *)kcontrol->private_value;
142 struct hsw_priv_data *pdata =
143 snd_soc_platform_get_drvdata(platform);
144 struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
145 struct sst_hsw *hsw = pdata->hsw;
146 u32 volume;
147
148 mutex_lock(&pcm_data->mutex);
149
150 if (!pcm_data->stream) {
151 pcm_data->volume[0] =
152 hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
153 pcm_data->volume[1] =
154 hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
155 mutex_unlock(&pcm_data->mutex);
156 return 0;
157 }
158
159 if (ucontrol->value.integer.value[0] ==
160 ucontrol->value.integer.value[1]) {
161 volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
162 sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 2, volume);
163 } else {
164 volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
165 sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 0, volume);
166 volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
167 sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume);
168 }
169
170 mutex_unlock(&pcm_data->mutex);
171 return 0;
172}
173
174static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
175 struct snd_ctl_elem_value *ucontrol)
176{
177 struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
178 struct soc_mixer_control *mc =
179 (struct soc_mixer_control *)kcontrol->private_value;
180 struct hsw_priv_data *pdata =
181 snd_soc_platform_get_drvdata(platform);
182 struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
183 struct sst_hsw *hsw = pdata->hsw;
184 u32 volume;
185
186 mutex_lock(&pcm_data->mutex);
187
188 if (!pcm_data->stream) {
189 ucontrol->value.integer.value[0] =
190 hsw_ipc_to_mixer(pcm_data->volume[0]);
191 ucontrol->value.integer.value[1] =
192 hsw_ipc_to_mixer(pcm_data->volume[1]);
193 mutex_unlock(&pcm_data->mutex);
194 return 0;
195 }
196
197 sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 0, &volume);
198 ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
199 sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume);
200 ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
201 mutex_unlock(&pcm_data->mutex);
202
203 return 0;
204}
205
206static int hsw_volume_put(struct snd_kcontrol *kcontrol,
207 struct snd_ctl_elem_value *ucontrol)
208{
209 struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
210 struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
211 struct sst_hsw *hsw = pdata->hsw;
212 u32 volume;
213
214 if (ucontrol->value.integer.value[0] ==
215 ucontrol->value.integer.value[1]) {
216
217 volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
218 sst_hsw_mixer_set_volume(hsw, 0, 2, volume);
219
220 } else {
221 volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
222 sst_hsw_mixer_set_volume(hsw, 0, 0, volume);
223
224 volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
225 sst_hsw_mixer_set_volume(hsw, 0, 1, volume);
226 }
227
228 return 0;
229}
230
231static int hsw_volume_get(struct snd_kcontrol *kcontrol,
232 struct snd_ctl_elem_value *ucontrol)
233{
234 struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
235 struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
236 struct sst_hsw *hsw = pdata->hsw;
237 unsigned int volume = 0;
238
239 sst_hsw_mixer_get_volume(hsw, 0, 0, &volume);
240 ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
241
242 sst_hsw_mixer_get_volume(hsw, 0, 1, &volume);
243 ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
244
245 return 0;
246}
247
248/* TLV used by both global and stream volumes */
249static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1);
250
251/* System Pin has no volume control */
252static const struct snd_kcontrol_new hsw_volume_controls[] = {
253 /* Global DSP volume */
254 SOC_DOUBLE_EXT_TLV("Master Playback Volume", 0, 0, 8,
255 ARRAY_SIZE(volume_map) -1, 0,
256 hsw_volume_get, hsw_volume_put, hsw_vol_tlv),
257 /* Offload 0 volume */
258 SOC_DOUBLE_EXT_TLV("Media0 Playback Volume", 1, 0, 8,
259 ARRAY_SIZE(volume_map), 0,
260 hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
261 /* Offload 1 volume */
262 SOC_DOUBLE_EXT_TLV("Media1 Playback Volume", 2, 0, 8,
263 ARRAY_SIZE(volume_map), 0,
264 hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
265 /* Loopback volume */
266 SOC_DOUBLE_EXT_TLV("Loopback Capture Volume", 3, 0, 8,
267 ARRAY_SIZE(volume_map), 0,
268 hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
269 /* Mic Capture volume */
270 SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8,
271 ARRAY_SIZE(volume_map), 0,
272 hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
273};
274
275/* Create DMA buffer page table for DSP */
276static int create_adsp_page_table(struct hsw_priv_data *pdata,
277 struct snd_soc_pcm_runtime *rtd,
278 unsigned char *dma_area, size_t size, int pcm, int stream)
279{
280 int i, pages;
281
282 if (size % PAGE_SIZE)
283 pages = (size / PAGE_SIZE) + 1;
284 else
285 pages = size / PAGE_SIZE;
286
287 dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n",
288 dma_area, size, pages);
289
290 for (i = 0; i < pages; i++) {
291 u32 idx = (((i << 2) + i)) >> 1;
292 u32 pfn = (virt_to_phys(dma_area + i * PAGE_SIZE)) >> PAGE_SHIFT;
293 u32 *pg_table;
294
295 dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
296
297 pg_table = (u32*)(pdata->pcm_pg[pcm][stream] + idx);
298
299 if (i & 1)
300 *pg_table |= (pfn << 4);
301 else
302 *pg_table |= pfn;
303 }
304
305 return 0;
306}
307
308/* this may get called several times by oss emulation */
309static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
310 struct snd_pcm_hw_params *params)
311{
312 struct snd_soc_pcm_runtime *rtd = substream->private_data;
313 struct snd_pcm_runtime *runtime = substream->runtime;
314 struct hsw_priv_data *pdata =
315 snd_soc_platform_get_drvdata(rtd->platform);
316 struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
317 struct sst_hsw *hsw = pdata->hsw;
318 struct sst_module *module_data;
319 struct sst_dsp *dsp;
320 enum sst_hsw_stream_type stream_type;
321 enum sst_hsw_stream_path_id path_id;
322 u32 rate, bits, map, pages, module_id;
323 u8 channels;
324 int ret;
325
326 /* stream direction */
327 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
328 path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
329 else
330 path_id = SST_HSW_STREAM_PATH_SSP0_IN;
331
332 /* DSP stream type depends on DAI ID */
333 switch (rtd->cpu_dai->id) {
334 case 0:
335 stream_type = SST_HSW_STREAM_TYPE_SYSTEM;
336 module_id = SST_HSW_MODULE_PCM_SYSTEM;
337 break;
338 case 1:
339 case 2:
340 stream_type = SST_HSW_STREAM_TYPE_RENDER;
341 module_id = SST_HSW_MODULE_PCM;
342 break;
343 case 3:
344 /* path ID needs to be OUT for loopback */
345 stream_type = SST_HSW_STREAM_TYPE_LOOPBACK;
346 path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
347 module_id = SST_HSW_MODULE_PCM_REFERENCE;
348 break;
349 case 4:
350 stream_type = SST_HSW_STREAM_TYPE_CAPTURE;
351 module_id = SST_HSW_MODULE_PCM_CAPTURE;
352 break;
353 default:
354 dev_err(rtd->dev, "error: invalid DAI ID %d\n",
355 rtd->cpu_dai->id);
356 return -EINVAL;
357 };
358
359 ret = sst_hsw_stream_format(hsw, pcm_data->stream,
360 path_id, stream_type, SST_HSW_STREAM_FORMAT_PCM_FORMAT);
361 if (ret < 0) {
362 dev_err(rtd->dev, "error: failed to set format %d\n", ret);
363 return ret;
364 }
365
366 rate = params_rate(params);
367 ret = sst_hsw_stream_set_rate(hsw, pcm_data->stream, rate);
368 if (ret < 0) {
369 dev_err(rtd->dev, "error: could not set rate %d\n", rate);
370 return ret;
371 }
372
373 switch (params_format(params)) {
374 case SNDRV_PCM_FORMAT_S16_LE:
375 bits = SST_HSW_DEPTH_16BIT;
376 sst_hsw_stream_set_valid(hsw, pcm_data->stream, 16);
377 break;
378 case SNDRV_PCM_FORMAT_S24_LE:
379 bits = SST_HSW_DEPTH_24BIT;
380 sst_hsw_stream_set_valid(hsw, pcm_data->stream, 32);
381 break;
382 default:
383 dev_err(rtd->dev, "error: invalid format %d\n",
384 params_format(params));
385 return -EINVAL;
386 }
387
388 ret = sst_hsw_stream_set_bits(hsw, pcm_data->stream, bits);
389 if (ret < 0) {
390 dev_err(rtd->dev, "error: could not set bits %d\n", bits);
391 return ret;
392 }
393
394 /* we only support stereo atm */
395 channels = params_channels(params);
396 if (channels != 2) {
397 dev_err(rtd->dev, "error: invalid channels %d\n", channels);
398 return -EINVAL;
399 }
400
401 map = create_channel_map(SST_HSW_CHANNEL_CONFIG_STEREO);
402 sst_hsw_stream_set_map_config(hsw, pcm_data->stream,
403 map, SST_HSW_CHANNEL_CONFIG_STEREO);
404
405 ret = sst_hsw_stream_set_channels(hsw, pcm_data->stream, channels);
406 if (ret < 0) {
407 dev_err(rtd->dev, "error: could not set channels %d\n",
408 channels);
409 return ret;
410 }
411
412 ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
413 if (ret < 0) {
414 dev_err(rtd->dev, "error: could not allocate %d bytes for PCM %d\n",
415 params_buffer_bytes(params), ret);
416 return ret;
417 }
418
419 ret = create_adsp_page_table(pdata, rtd, runtime->dma_area,
420 runtime->dma_bytes, rtd->cpu_dai->id, substream->stream);
421 if (ret < 0)
422 return ret;
423
424 sst_hsw_stream_set_style(hsw, pcm_data->stream,
425 SST_HSW_INTERLEAVING_PER_CHANNEL);
426
427 if (runtime->dma_bytes % PAGE_SIZE)
428 pages = (runtime->dma_bytes / PAGE_SIZE) + 1;
429 else
430 pages = runtime->dma_bytes / PAGE_SIZE;
431
432 ret = sst_hsw_stream_buffer(hsw, pcm_data->stream,
433 virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]),
434 pages, runtime->dma_bytes, 0,
435 (u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT));
436 if (ret < 0) {
437 dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret);
438 return ret;
439 }
440
441 dsp = sst_hsw_get_dsp(hsw);
442
443 module_data = sst_module_get_from_id(dsp, module_id);
444 if (module_data == NULL) {
445 dev_err(rtd->dev, "error: failed to get module config\n");
446 return -EINVAL;
447 }
448
449 /* we use hardcoded memory offsets atm, will be updated for new FW */
450 if (stream_type == SST_HSW_STREAM_TYPE_CAPTURE) {
451 sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
452 SST_HSW_MODULE_PCM_CAPTURE, module_data->entry);
453 sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
454 0x449400, 0x4000);
455 sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
456 0x400000, 0);
457 } else { /* stream_type == SST_HSW_STREAM_TYPE_SYSTEM */
458 sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
459 SST_HSW_MODULE_PCM_SYSTEM, module_data->entry);
460
461 sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
462 module_data->offset, module_data->size);
463 sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
464 0x44d400, 0x3800);
465
466 sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
467 module_data->offset, module_data->size);
468 sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
469 0x400000, 0);
470 }
471
472 ret = sst_hsw_stream_commit(hsw, pcm_data->stream);
473 if (ret < 0) {
474 dev_err(rtd->dev, "error: failed to commit stream %d\n", ret);
475 return ret;
476 }
477
478 ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1);
479 if (ret < 0)
480 dev_err(rtd->dev, "error: failed to pause %d\n", ret);
481
482 return 0;
483}
484
485static int hsw_pcm_hw_free(struct snd_pcm_substream *substream)
486{
487 snd_pcm_lib_free_pages(substream);
488 return 0;
489}
490
491static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
492{
493 struct snd_soc_pcm_runtime *rtd = substream->private_data;
494 struct hsw_priv_data *pdata =
495 snd_soc_platform_get_drvdata(rtd->platform);
496 struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
497 struct sst_hsw *hsw = pdata->hsw;
498
499 switch (cmd) {
500 case SNDRV_PCM_TRIGGER_START:
501 case SNDRV_PCM_TRIGGER_RESUME:
502 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
503 sst_hsw_stream_resume(hsw, pcm_data->stream, 0);
504 break;
505 case SNDRV_PCM_TRIGGER_STOP:
506 case SNDRV_PCM_TRIGGER_SUSPEND:
507 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
508 sst_hsw_stream_pause(hsw, pcm_data->stream, 0);
509 break;
510 default:
511 break;
512 }
513
514 return 0;
515}
516
517static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data)
518{
519 struct hsw_pcm_data *pcm_data = data;
520 struct snd_pcm_substream *substream = pcm_data->substream;
521 struct snd_pcm_runtime *runtime = substream->runtime;
522 struct snd_soc_pcm_runtime *rtd = substream->private_data;
523 u32 pos;
524
525 pos = frames_to_bytes(runtime,
526 (runtime->control->appl_ptr % runtime->buffer_size));
527
528 dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
529
530 /* let alsa know we have play a period */
531 snd_pcm_period_elapsed(substream);
532 return pos;
533}
534
535static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
536{
537 struct snd_soc_pcm_runtime *rtd = substream->private_data;
538 struct snd_pcm_runtime *runtime = substream->runtime;
539 struct hsw_priv_data *pdata =
540 snd_soc_platform_get_drvdata(rtd->platform);
541 struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
542 struct sst_hsw *hsw = pdata->hsw;
543 snd_pcm_uframes_t offset;
544
545 offset = bytes_to_frames(runtime,
546 sst_hsw_get_dsp_position(hsw, pcm_data->stream));
547
548 dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n",
549 frames_to_bytes(runtime, (u32)offset));
550 return offset;
551}
552
553static int hsw_pcm_open(struct snd_pcm_substream *substream)
554{
555 struct snd_soc_pcm_runtime *rtd = substream->private_data;
556 struct hsw_priv_data *pdata =
557 snd_soc_platform_get_drvdata(rtd->platform);
558 struct hsw_pcm_data *pcm_data;
559 struct sst_hsw *hsw = pdata->hsw;
560
561 pcm_data = &pdata->pcm[rtd->cpu_dai->id];
562
563 mutex_lock(&pcm_data->mutex);
564
565 snd_soc_pcm_set_drvdata(rtd, pcm_data);
566 pcm_data->substream = substream;
567
568 snd_soc_set_runtime_hwparams(substream, &hsw_pcm_hardware);
569
570 pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id,
571 hsw_notify_pointer, pcm_data);
572 if (pcm_data->stream == NULL) {
573 dev_err(rtd->dev, "error: failed to create stream\n");
574 mutex_unlock(&pcm_data->mutex);
575 return -EINVAL;
576 }
577
578 /* Set previous saved volume */
579 sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
580 0, pcm_data->volume[0]);
581 sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
582 1, pcm_data->volume[1]);
583
584 mutex_unlock(&pcm_data->mutex);
585 return 0;
586}
587
588static int hsw_pcm_close(struct snd_pcm_substream *substream)
589{
590 struct snd_soc_pcm_runtime *rtd = substream->private_data;
591 struct hsw_priv_data *pdata =
592 snd_soc_platform_get_drvdata(rtd->platform);
593 struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
594 struct sst_hsw *hsw = pdata->hsw;
595 int ret;
596
597 mutex_lock(&pcm_data->mutex);
598 ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
599 if (ret < 0) {
600 dev_dbg(rtd->dev, "error: reset stream failed %d\n", ret);
601 goto out;
602 }
603
604 ret = sst_hsw_stream_free(hsw, pcm_data->stream);
605 if (ret < 0) {
606 dev_dbg(rtd->dev, "error: free stream failed %d\n", ret);
607 goto out;
608 }
609 pcm_data->stream = NULL;
610
611out:
612 mutex_unlock(&pcm_data->mutex);
613 return ret;
614}
615
616static struct snd_pcm_ops hsw_pcm_ops = {
617 .open = hsw_pcm_open,
618 .close = hsw_pcm_close,
619 .ioctl = snd_pcm_lib_ioctl,
620 .hw_params = hsw_pcm_hw_params,
621 .hw_free = hsw_pcm_hw_free,
622 .trigger = hsw_pcm_trigger,
623 .pointer = hsw_pcm_pointer,
624 .mmap = snd_pcm_lib_default_mmap,
625};
626
627static void hsw_pcm_free(struct snd_pcm *pcm)
628{
629 snd_pcm_lib_preallocate_free_for_all(pcm);
630}
631
632static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
633{
634 struct snd_pcm *pcm = rtd->pcm;
635 int ret = 0;
636
637 ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32));
638 if (ret)
639 return ret;
640
641 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
642 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
643 ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
644 SNDRV_DMA_TYPE_DEV,
645 rtd->card->dev,
646 hsw_pcm_hardware.buffer_bytes_max,
647 hsw_pcm_hardware.buffer_bytes_max);
648 if (ret) {
649 dev_err(rtd->dev, "dma buffer allocation failed %d\n",
650 ret);
651 return ret;
652 }
653 }
654
655 return ret;
656}
657
658#define HSW_FORMATS \
659 (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE |\
660 SNDRV_PCM_FMTBIT_S32_LE)
661
662static struct snd_soc_dai_driver hsw_dais[] = {
663 {
664 .name = "System Pin",
665 .playback = {
666 .stream_name = "System Playback",
667 .channels_min = 2,
668 .channels_max = 2,
669 .rates = SNDRV_PCM_RATE_48000,
670 .formats = SNDRV_PCM_FMTBIT_S16_LE,
671 },
672 },
673 {
674 /* PCM */
675 .name = "Offload0 Pin",
676 .playback = {
677 .stream_name = "Offload0 Playback",
678 .channels_min = 2,
679 .channels_max = 2,
680 .rates = SNDRV_PCM_RATE_8000_192000,
681 .formats = HSW_FORMATS,
682 },
683 },
684 {
685 /* PCM */
686 .name = "Offload1 Pin",
687 .playback = {
688 .stream_name = "Offload1 Playback",
689 .channels_min = 2,
690 .channels_max = 2,
691 .rates = SNDRV_PCM_RATE_8000_192000,
692 .formats = HSW_FORMATS,
693 },
694 },
695 {
696 .name = "Loopback Pin",
697 .capture = {
698 .stream_name = "Loopback Capture",
699 .channels_min = 2,
700 .channels_max = 2,
701 .rates = SNDRV_PCM_RATE_8000_192000,
702 .formats = HSW_FORMATS,
703 },
704 },
705 {
706 .name = "Capture Pin",
707 .capture = {
708 .stream_name = "Analog Capture",
709 .channels_min = 2,
710 .channels_max = 2,
711 .rates = SNDRV_PCM_RATE_8000_192000,
712 .formats = HSW_FORMATS,
713 },
714 },
715};
716
717static const struct snd_soc_dapm_widget widgets[] = {
718
719 /* Backend DAIs */
720 SND_SOC_DAPM_AIF_IN("SSP0 CODEC IN", NULL, 0, SND_SOC_NOPM, 0, 0),
721 SND_SOC_DAPM_AIF_OUT("SSP0 CODEC OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
722 SND_SOC_DAPM_AIF_IN("SSP1 BT IN", NULL, 0, SND_SOC_NOPM, 0, 0),
723 SND_SOC_DAPM_AIF_OUT("SSP1 BT OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
724
725 /* Global Playback Mixer */
726 SND_SOC_DAPM_MIXER("Playback VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
727};
728
729static const struct snd_soc_dapm_route graph[] = {
730
731 /* Playback Mixer */
732 {"Playback VMixer", NULL, "System Playback"},
733 {"Playback VMixer", NULL, "Offload0 Playback"},
734 {"Playback VMixer", NULL, "Offload1 Playback"},
735
736 {"SSP0 CODEC OUT", NULL, "Playback VMixer"},
737
738 {"Analog Capture", NULL, "SSP0 CODEC IN"},
739};
740
741static int hsw_pcm_probe(struct snd_soc_platform *platform)
742{
743 struct sst_pdata *pdata = dev_get_platdata(platform->dev);
744 struct hsw_priv_data *priv_data;
745 int i;
746
747 if (!pdata)
748 return -ENODEV;
749
750 priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL);
751 priv_data->hsw = pdata->dsp;
752 snd_soc_platform_set_drvdata(platform, priv_data);
753
754 /* allocate DSP buffer page tables */
755 for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
756
757 mutex_init(&priv_data->pcm[i].mutex);
758
759 /* playback */
760 if (hsw_dais[i].playback.channels_min) {
761 priv_data->pcm_pg[i][0] = kzalloc(PAGE_SIZE, GFP_DMA);
762 if (priv_data->pcm_pg[i][0] == NULL)
763 goto err;
764 }
765
766 /* capture */
767 if (hsw_dais[i].capture.channels_min) {
768 priv_data->pcm_pg[i][1] = kzalloc(PAGE_SIZE, GFP_DMA);
769 if (priv_data->pcm_pg[i][1] == NULL)
770 goto err;
771 }
772 }
773
774 return 0;
775
776err:
777 for (;i >= 0; i--) {
778 if (hsw_dais[i].playback.channels_min)
779 kfree(priv_data->pcm_pg[i][0]);
780 if (hsw_dais[i].capture.channels_min)
781 kfree(priv_data->pcm_pg[i][1]);
782 }
783 return -ENOMEM;
784}
785
786static int hsw_pcm_remove(struct snd_soc_platform *platform)
787{
788 struct hsw_priv_data *priv_data =
789 snd_soc_platform_get_drvdata(platform);
790 int i;
791
792 for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
793 if (hsw_dais[i].playback.channels_min)
794 kfree(priv_data->pcm_pg[i][0]);
795 if (hsw_dais[i].capture.channels_min)
796 kfree(priv_data->pcm_pg[i][1]);
797 }
798
799 return 0;
800}
801
802static struct snd_soc_platform_driver hsw_soc_platform = {
803 .probe = hsw_pcm_probe,
804 .remove = hsw_pcm_remove,
805 .ops = &hsw_pcm_ops,
806 .pcm_new = hsw_pcm_new,
807 .pcm_free = hsw_pcm_free,
808 .controls = hsw_volume_controls,
809 .num_controls = ARRAY_SIZE(hsw_volume_controls),
810 .dapm_widgets = widgets,
811 .num_dapm_widgets = ARRAY_SIZE(widgets),
812 .dapm_routes = graph,
813 .num_dapm_routes = ARRAY_SIZE(graph),
814};
815
816static const struct snd_soc_component_driver hsw_dai_component = {
817 .name = "haswell-dai",
818};
819
820static int hsw_pcm_dev_probe(struct platform_device *pdev)
821{
822 struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
823 int ret;
824
825 ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata);
826 if (ret < 0)
827 return -ENODEV;
828
829 ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform);
830 if (ret < 0)
831 goto err_plat;
832
833 ret = snd_soc_register_component(&pdev->dev, &hsw_dai_component,
834 hsw_dais, ARRAY_SIZE(hsw_dais));
835 if (ret < 0)
836 goto err_comp;
837
838 return 0;
839
840err_comp:
841 snd_soc_unregister_platform(&pdev->dev);
842err_plat:
843 sst_hsw_dsp_free(&pdev->dev, sst_pdata);
844 return 0;
845}
846
847static int hsw_pcm_dev_remove(struct platform_device *pdev)
848{
849 struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
850
851 snd_soc_unregister_platform(&pdev->dev);
852 snd_soc_unregister_component(&pdev->dev);
853 sst_hsw_dsp_free(&pdev->dev, sst_pdata);
854
855 return 0;
856}
857
858static struct platform_driver hsw_pcm_driver = {
859 .driver = {
860 .name = "haswell-pcm-audio",
861 .owner = THIS_MODULE,
862 },
863
864 .probe = hsw_pcm_dev_probe,
865 .remove = hsw_pcm_dev_remove,
866};
867module_platform_driver(hsw_pcm_driver);
868
869MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
870MODULE_DESCRIPTION("Haswell/Lynxpoint + Broadwell/Wildcatpoint PCM");
871MODULE_LICENSE("GPL v2");
872MODULE_ALIAS("platform:haswell-pcm-audio");
diff --git a/sound/soc/intel/sst_dsp.h b/sound/soc/intel/sst-mfld-dsp.h
index 0fce1de284ff..3b63edc04b7f 100644
--- a/sound/soc/intel/sst_dsp.h
+++ b/sound/soc/intel/sst-mfld-dsp.h
@@ -1,7 +1,7 @@
1#ifndef __SST_DSP_H__ 1#ifndef __SST_MFLD_DSP_H__
2#define __SST_DSP_H__ 2#define __SST_MFLD_DSP_H__
3/* 3/*
4 * sst_dsp.h - Intel SST Driver for audio engine 4 * sst_mfld_dsp.h - Intel SST Driver for audio engine
5 * 5 *
6 * Copyright (C) 2008-12 Intel Corporation 6 * Copyright (C) 2008-12 Intel Corporation
7 * Authors: Vinod Koul <vinod.koul@linux.intel.com> 7 * Authors: Vinod Koul <vinod.koul@linux.intel.com>
@@ -131,4 +131,4 @@ struct snd_sst_params {
131 struct snd_sst_alloc_params_ext aparams; 131 struct snd_sst_alloc_params_ext aparams;
132}; 132};
133 133
134#endif /* __SST_DSP_H__ */ 134#endif /* __SST_MFLD_DSP_H__ */
diff --git a/sound/soc/intel/sst_platform.c b/sound/soc/intel/sst-mfld-platform.c
index f465a8180863..840306c2ef14 100644
--- a/sound/soc/intel/sst_platform.c
+++ b/sound/soc/intel/sst-mfld-platform.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * sst_platform.c - Intel MID Platform driver 2 * sst_mfld_platform.c - Intel MID Platform driver
3 * 3 *
4 * Copyright (C) 2010-2013 Intel Corp 4 * Copyright (C) 2010-2013 Intel Corp
5 * Author: Vinod Koul <vinod.koul@intel.com> 5 * Author: Vinod Koul <vinod.koul@intel.com>
@@ -33,7 +33,7 @@
33#include <sound/pcm_params.h> 33#include <sound/pcm_params.h>
34#include <sound/soc.h> 34#include <sound/soc.h>
35#include <sound/compress_driver.h> 35#include <sound/compress_driver.h>
36#include "sst_platform.h" 36#include "sst-mfld-platform.h"
37 37
38static struct sst_device *sst; 38static struct sst_device *sst;
39static DEFINE_MUTEX(sst_lock); 39static DEFINE_MUTEX(sst_lock);
@@ -709,7 +709,7 @@ static int sst_platform_remove(struct platform_device *pdev)
709 709
710static struct platform_driver sst_platform_driver = { 710static struct platform_driver sst_platform_driver = {
711 .driver = { 711 .driver = {
712 .name = "sst-platform", 712 .name = "sst-mfld-platform",
713 .owner = THIS_MODULE, 713 .owner = THIS_MODULE,
714 }, 714 },
715 .probe = sst_platform_probe, 715 .probe = sst_platform_probe,
@@ -722,4 +722,4 @@ MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
722MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); 722MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
723MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); 723MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
724MODULE_LICENSE("GPL v2"); 724MODULE_LICENSE("GPL v2");
725MODULE_ALIAS("platform:sst-platform"); 725MODULE_ALIAS("platform:sst-mfld-platform");
diff --git a/sound/soc/intel/sst_platform.h b/sound/soc/intel/sst-mfld-platform.h
index bee64fb7d2ef..0c4e2ddcecb1 100644
--- a/sound/soc/intel/sst_platform.h
+++ b/sound/soc/intel/sst-mfld-platform.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * sst_platform.h - Intel MID Platform driver header file 2 * sst_mfld_platform.h - Intel MID Platform driver header file
3 * 3 *
4 * Copyright (C) 2010 Intel Corp 4 * Copyright (C) 2010 Intel Corp
5 * Author: Vinod Koul <vinod.koul@intel.com> 5 * Author: Vinod Koul <vinod.koul@intel.com>
@@ -27,7 +27,7 @@
27#ifndef __SST_PLATFORMDRV_H__ 27#ifndef __SST_PLATFORMDRV_H__
28#define __SST_PLATFORMDRV_H__ 28#define __SST_PLATFORMDRV_H__
29 29
30#include "sst_dsp.h" 30#include "sst-mfld-dsp.h"
31 31
32#define SST_MONO 1 32#define SST_MONO 1
33#define SST_STEREO 2 33#define SST_STEREO 2