diff options
author | Mark Brown <broonie@kernel.org> | 2016-09-29 15:43:59 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-09-29 15:43:59 -0400 |
commit | 4a2447b483e17c580ed1d7c9cde3267d9c3a380f (patch) | |
tree | d4845df7d877abe55229b97f16359509c1eea140 | |
parent | 00f12dbd3c33bb46b2d5e122406410b325b2c77d (diff) | |
parent | 0730bd2e2ade00d88647b13a0c17cde254ddf56e (diff) |
Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
38 files changed, 2907 insertions, 485 deletions
diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index ff1aecf325e8..0013063db7f2 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h | |||
@@ -89,6 +89,19 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
89 | #define AZX_REG_SD_BDLPL 0x18 | 89 | #define AZX_REG_SD_BDLPL 0x18 |
90 | #define AZX_REG_SD_BDLPU 0x1c | 90 | #define AZX_REG_SD_BDLPU 0x1c |
91 | 91 | ||
92 | /* GTS registers */ | ||
93 | #define AZX_REG_LLCH 0x14 | ||
94 | |||
95 | #define AZX_REG_GTS_BASE 0x520 | ||
96 | |||
97 | #define AZX_REG_GTSCC (AZX_REG_GTS_BASE + 0x00) | ||
98 | #define AZX_REG_WALFCC (AZX_REG_GTS_BASE + 0x04) | ||
99 | #define AZX_REG_TSCCL (AZX_REG_GTS_BASE + 0x08) | ||
100 | #define AZX_REG_TSCCU (AZX_REG_GTS_BASE + 0x0C) | ||
101 | #define AZX_REG_LLPFOC (AZX_REG_GTS_BASE + 0x14) | ||
102 | #define AZX_REG_LLPCL (AZX_REG_GTS_BASE + 0x18) | ||
103 | #define AZX_REG_LLPCU (AZX_REG_GTS_BASE + 0x1C) | ||
104 | |||
92 | /* Haswell/Broadwell display HD-A controller Extended Mode registers */ | 105 | /* Haswell/Broadwell display HD-A controller Extended Mode registers */ |
93 | #define AZX_REG_HSW_EM4 0x100c | 106 | #define AZX_REG_HSW_EM4 0x100c |
94 | #define AZX_REG_HSW_EM5 0x1010 | 107 | #define AZX_REG_HSW_EM5 0x1010 |
@@ -242,6 +255,29 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
242 | /* Interval used to calculate the iterating register offset */ | 255 | /* Interval used to calculate the iterating register offset */ |
243 | #define AZX_DRSM_INTERVAL 0x08 | 256 | #define AZX_DRSM_INTERVAL 0x08 |
244 | 257 | ||
258 | /* Global time synchronization registers */ | ||
259 | #define GTSCC_TSCCD_MASK 0x80000000 | ||
260 | #define GTSCC_TSCCD_SHIFT BIT(31) | ||
261 | #define GTSCC_TSCCI_MASK 0x20 | ||
262 | #define GTSCC_CDMAS_DMA_DIR_SHIFT 4 | ||
263 | |||
264 | #define WALFCC_CIF_MASK 0x1FF | ||
265 | #define WALFCC_FN_SHIFT 9 | ||
266 | #define HDA_CLK_CYCLES_PER_FRAME 512 | ||
267 | |||
268 | /* | ||
269 | * An error occurs near frame "rollover". The clocks in frame value indicates | ||
270 | * whether this error may have occurred. Here we use the value of 10. Please | ||
271 | * see the errata for the right number [<10] | ||
272 | */ | ||
273 | #define HDA_MAX_CYCLE_VALUE 499 | ||
274 | #define HDA_MAX_CYCLE_OFFSET 10 | ||
275 | #define HDA_MAX_CYCLE_READ_RETRY 10 | ||
276 | |||
277 | #define TSCCU_CCU_SHIFT 32 | ||
278 | #define LLPC_CCU_SHIFT 32 | ||
279 | |||
280 | |||
245 | /* | 281 | /* |
246 | * helpers to read the stream position | 282 | * helpers to read the stream position |
247 | */ | 283 | */ |
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 93e63c56f48f..56004ec8d441 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h | |||
@@ -245,6 +245,12 @@ struct hdac_rb { | |||
245 | 245 | ||
246 | /* | 246 | /* |
247 | * HD-audio bus base driver | 247 | * HD-audio bus base driver |
248 | * | ||
249 | * @ppcap: pp capabilities pointer | ||
250 | * @spbcap: SPIB capabilities pointer | ||
251 | * @mlcap: MultiLink capabilities pointer | ||
252 | * @gtscap: gts capabilities pointer | ||
253 | * @drsmcap: dma resume capabilities pointer | ||
248 | */ | 254 | */ |
249 | struct hdac_bus { | 255 | struct hdac_bus { |
250 | struct device *dev; | 256 | struct device *dev; |
@@ -256,6 +262,12 @@ struct hdac_bus { | |||
256 | void __iomem *remap_addr; | 262 | void __iomem *remap_addr; |
257 | int irq; | 263 | int irq; |
258 | 264 | ||
265 | void __iomem *ppcap; | ||
266 | void __iomem *spbcap; | ||
267 | void __iomem *mlcap; | ||
268 | void __iomem *gtscap; | ||
269 | void __iomem *drsmcap; | ||
270 | |||
259 | /* codec linked list */ | 271 | /* codec linked list */ |
260 | struct list_head codec_list; | 272 | struct list_head codec_list; |
261 | unsigned int num_codecs; | 273 | unsigned int num_codecs; |
@@ -335,6 +347,7 @@ static inline void snd_hdac_codec_link_down(struct hdac_device *codec) | |||
335 | int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val); | 347 | int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val); |
336 | int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, | 348 | int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, |
337 | unsigned int *res); | 349 | unsigned int *res); |
350 | int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus); | ||
338 | int snd_hdac_link_power(struct hdac_device *codec, bool enable); | 351 | int snd_hdac_link_power(struct hdac_device *codec, bool enable); |
339 | 352 | ||
340 | bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset); | 353 | bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset); |
diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index b9593b201599..8660a7f10851 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h | |||
@@ -8,11 +8,6 @@ | |||
8 | * | 8 | * |
9 | * @bus: hdac bus | 9 | * @bus: hdac bus |
10 | * @num_streams: streams supported | 10 | * @num_streams: streams supported |
11 | * @ppcap: pp capabilities pointer | ||
12 | * @spbcap: SPIB capabilities pointer | ||
13 | * @mlcap: MultiLink capabilities pointer | ||
14 | * @gtscap: gts capabilities pointer | ||
15 | * @drsmcap: dma resume capabilities pointer | ||
16 | * @hlink_list: link list of HDA links | 11 | * @hlink_list: link list of HDA links |
17 | * @lock: lock for link mgmt | 12 | * @lock: lock for link mgmt |
18 | * @cmd_dma_state: state of cmd DMAs: CORB and RIRB | 13 | * @cmd_dma_state: state of cmd DMAs: CORB and RIRB |
@@ -22,12 +17,6 @@ struct hdac_ext_bus { | |||
22 | int num_streams; | 17 | int num_streams; |
23 | int idx; | 18 | int idx; |
24 | 19 | ||
25 | void __iomem *ppcap; | ||
26 | void __iomem *spbcap; | ||
27 | void __iomem *mlcap; | ||
28 | void __iomem *gtscap; | ||
29 | void __iomem *drsmcap; | ||
30 | |||
31 | struct list_head hlink_list; | 20 | struct list_head hlink_list; |
32 | 21 | ||
33 | struct mutex lock; | 22 | struct mutex lock; |
@@ -54,7 +43,6 @@ void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus); | |||
54 | #define HDA_CODEC_EXT_ENTRY(_vid, _revid, _name, _drv_data) \ | 43 | #define HDA_CODEC_EXT_ENTRY(_vid, _revid, _name, _drv_data) \ |
55 | HDA_CODEC_REV_EXT_ENTRY(_vid, _revid, _name, _drv_data) | 44 | HDA_CODEC_REV_EXT_ENTRY(_vid, _revid, _name, _drv_data) |
56 | 45 | ||
57 | int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *sbus); | ||
58 | void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *chip, bool enable); | 46 | void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *chip, bool enable); |
59 | void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *chip, bool enable); | 47 | void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *chip, bool enable); |
60 | 48 | ||
diff --git a/include/uapi/sound/Kbuild b/include/uapi/sound/Kbuild index 691984cb0b91..9578d8bdbf31 100644 --- a/include/uapi/sound/Kbuild +++ b/include/uapi/sound/Kbuild | |||
@@ -13,3 +13,4 @@ header-y += sb16_csp.h | |||
13 | header-y += sfnt_info.h | 13 | header-y += sfnt_info.h |
14 | header-y += tlv.h | 14 | header-y += tlv.h |
15 | header-y += usb_stream.h | 15 | header-y += usb_stream.h |
16 | header-y += snd_sst_tokens.h | ||
diff --git a/include/uapi/sound/snd_sst_tokens.h b/include/uapi/sound/snd_sst_tokens.h new file mode 100644 index 000000000000..1ee2e943d66a --- /dev/null +++ b/include/uapi/sound/snd_sst_tokens.h | |||
@@ -0,0 +1,214 @@ | |||
1 | /* | ||
2 | * snd_sst_tokens.h - Intel SST tokens definition | ||
3 | * | ||
4 | * Copyright (C) 2016 Intel Corp | ||
5 | * Author: Shreyas NC <shreyas.nc@intel.com> | ||
6 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as version 2, as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | */ | ||
17 | #ifndef __SND_SST_TOKENS_H__ | ||
18 | #define __SND_SST_TOKENS_H__ | ||
19 | |||
20 | /** | ||
21 | * %SKL_TKN_UUID: Module UUID | ||
22 | * | ||
23 | * %SKL_TKN_U8_BLOCK_TYPE: Type of the private data block.Can be: | ||
24 | * tuples, bytes, short and words | ||
25 | * | ||
26 | * %SKL_TKN_U8_IN_PIN_TYPE: Input pin type, | ||
27 | * homogenous=0, heterogenous=1 | ||
28 | * | ||
29 | * %SKL_TKN_U8_OUT_PIN_TYPE: Output pin type, | ||
30 | * homogenous=0, heterogenous=1 | ||
31 | * %SKL_TKN_U8_DYN_IN_PIN: Configure Input pin dynamically | ||
32 | * if true | ||
33 | * | ||
34 | * %SKL_TKN_U8_DYN_OUT_PIN: Configure Output pin dynamically | ||
35 | * if true | ||
36 | * | ||
37 | * %SKL_TKN_U8_IN_QUEUE_COUNT: Store the number of Input pins | ||
38 | * | ||
39 | * %SKL_TKN_U8_OUT_QUEUE_COUNT: Store the number of Output pins | ||
40 | * | ||
41 | * %SKL_TKN_U8_TIME_SLOT: TDM slot number | ||
42 | * | ||
43 | * %SKL_TKN_U8_CORE_ID: Stores module affinity value.Can take | ||
44 | * the values: | ||
45 | * SKL_AFFINITY_CORE_0 = 0, | ||
46 | * SKL_AFFINITY_CORE_1, | ||
47 | * SKL_AFFINITY_CORE_MAX | ||
48 | * | ||
49 | * %SKL_TKN_U8_MOD_TYPE: Module type value. | ||
50 | * | ||
51 | * %SKL_TKN_U8_CONN_TYPE: Module connection type can be a FE, | ||
52 | * BE or NONE as defined : | ||
53 | * SKL_PIPE_CONN_TYPE_NONE = 0, | ||
54 | * SKL_PIPE_CONN_TYPE_FE = 1 (HOST_DMA) | ||
55 | * SKL_PIPE_CONN_TYPE_BE = 2 (LINK_DMA) | ||
56 | * | ||
57 | * %SKL_TKN_U8_DEV_TYPE: Type of device to which the module is | ||
58 | * connected | ||
59 | * Can take the values: | ||
60 | * SKL_DEVICE_BT = 0x0, | ||
61 | * SKL_DEVICE_DMIC = 0x1, | ||
62 | * SKL_DEVICE_I2S = 0x2, | ||
63 | * SKL_DEVICE_SLIMBUS = 0x3, | ||
64 | * SKL_DEVICE_HDALINK = 0x4, | ||
65 | * SKL_DEVICE_HDAHOST = 0x5, | ||
66 | * SKL_DEVICE_NONE | ||
67 | * | ||
68 | * %SKL_TKN_U8_HW_CONN_TYPE: Connection type of the HW to which the | ||
69 | * module is connected | ||
70 | * SKL_CONN_NONE = 0, | ||
71 | * SKL_CONN_SOURCE = 1, | ||
72 | * SKL_CONN_SINK = 2 | ||
73 | * | ||
74 | * %SKL_TKN_U16_PIN_INST_ID: Stores the pin instance id | ||
75 | * | ||
76 | * %SKL_TKN_U16_MOD_INST_ID: Stores the mdule instance id | ||
77 | * | ||
78 | * %SKL_TKN_U32_MAX_MCPS: Module max mcps value | ||
79 | * | ||
80 | * %SKL_TKN_U32_MEM_PAGES: Module resource pages | ||
81 | * | ||
82 | * %SKL_TKN_U32_OBS: Stores Output Buffer size | ||
83 | * | ||
84 | * %SKL_TKN_U32_IBS: Stores input buffer size | ||
85 | * | ||
86 | * %SKL_TKN_U32_VBUS_ID: Module VBUS_ID. PDM=0, SSP0=0, | ||
87 | * SSP1=1,SSP2=2, | ||
88 | * SSP3=3, SSP4=4, | ||
89 | * SSP5=5, SSP6=6,INVALID | ||
90 | * | ||
91 | * %SKL_TKN_U32_PARAMS_FIXUP: Module Params fixup mask | ||
92 | * %SKL_TKN_U32_CONVERTER: Module params converter mask | ||
93 | * %SKL_TKN_U32_PIPE_ID: Stores the pipe id | ||
94 | * | ||
95 | * %SKL_TKN_U32_PIPE_CONN_TYPE: Type of the token to which the pipe is | ||
96 | * connected to. It can be | ||
97 | * SKL_PIPE_CONN_TYPE_NONE = 0, | ||
98 | * SKL_PIPE_CONN_TYPE_FE = 1 (HOST_DMA), | ||
99 | * SKL_PIPE_CONN_TYPE_BE = 2 (LINK_DMA), | ||
100 | * | ||
101 | * %SKL_TKN_U32_PIPE_PRIORITY: Pipe priority value | ||
102 | * %SKL_TKN_U32_PIPE_MEM_PGS: Pipe resource pages | ||
103 | * | ||
104 | * %SKL_TKN_U32_DIR_PIN_COUNT: Value for the direction to set input/output | ||
105 | * formats and the pin count. | ||
106 | * The first 4 bits have the direction | ||
107 | * value and the next 4 have | ||
108 | * the pin count value. | ||
109 | * SKL_DIR_IN = 0, SKL_DIR_OUT = 1. | ||
110 | * The input and output formats | ||
111 | * share the same set of tokens | ||
112 | * with the distinction between input | ||
113 | * and output made by reading direction | ||
114 | * token. | ||
115 | * | ||
116 | * %SKL_TKN_U32_FMT_CH: Supported channel count | ||
117 | * | ||
118 | * %SKL_TKN_U32_FMT_FREQ: Supported frequency/sample rate | ||
119 | * | ||
120 | * %SKL_TKN_U32_FMT_BIT_DEPTH: Supported container size | ||
121 | * | ||
122 | * %SKL_TKN_U32_FMT_SAMPLE_SIZE:Number of samples in the container | ||
123 | * | ||
124 | * %SKL_TKN_U32_FMT_CH_CONFIG: Supported channel configurations for the | ||
125 | * input/output. | ||
126 | * | ||
127 | * %SKL_TKN_U32_FMT_INTERLEAVE: Interleaving style which can be per | ||
128 | * channel or per sample. The values can be : | ||
129 | * SKL_INTERLEAVING_PER_CHANNEL = 0, | ||
130 | * SKL_INTERLEAVING_PER_SAMPLE = 1, | ||
131 | * | ||
132 | * %SKL_TKN_U32_FMT_SAMPLE_TYPE: | ||
133 | * Specifies the sample type. Can take the | ||
134 | * values: SKL_SAMPLE_TYPE_INT_MSB = 0, | ||
135 | * SKL_SAMPLE_TYPE_INT_LSB = 1, | ||
136 | * SKL_SAMPLE_TYPE_INT_SIGNED = 2, | ||
137 | * SKL_SAMPLE_TYPE_INT_UNSIGNED = 3, | ||
138 | * SKL_SAMPLE_TYPE_FLOAT = 4 | ||
139 | * | ||
140 | * %SKL_TKN_U32_CH_MAP: Channel map values | ||
141 | * %SKL_TKN_U32_MOD_SET_PARAMS: It can take these values: | ||
142 | * SKL_PARAM_DEFAULT, SKL_PARAM_INIT, | ||
143 | * SKL_PARAM_SET, SKL_PARAM_BIND | ||
144 | * | ||
145 | * %SKL_TKN_U32_MOD_PARAM_ID: ID of the module params | ||
146 | * | ||
147 | * %SKL_TKN_U32_CAPS_SET_PARAMS: | ||
148 | * Set params value | ||
149 | * | ||
150 | * %SKL_TKN_U32_CAPS_PARAMS_ID: Params ID | ||
151 | * | ||
152 | * %SKL_TKN_U32_CAPS_SIZE: Caps size | ||
153 | * | ||
154 | * %SKL_TKN_U32_PROC_DOMAIN: Specify processing domain | ||
155 | * | ||
156 | * %SKL_TKN_U32_LIB_COUNT: Specifies the number of libraries | ||
157 | * | ||
158 | * %SKL_TKN_STR_LIB_NAME: Specifies the library name | ||
159 | * | ||
160 | * module_id and loadable flags dont have tokens as these values will be | ||
161 | * read from the DSP FW manifest | ||
162 | */ | ||
163 | enum SKL_TKNS { | ||
164 | SKL_TKN_UUID = 1, | ||
165 | SKL_TKN_U8_NUM_BLOCKS, | ||
166 | SKL_TKN_U8_BLOCK_TYPE, | ||
167 | SKL_TKN_U8_IN_PIN_TYPE, | ||
168 | SKL_TKN_U8_OUT_PIN_TYPE, | ||
169 | SKL_TKN_U8_DYN_IN_PIN, | ||
170 | SKL_TKN_U8_DYN_OUT_PIN, | ||
171 | SKL_TKN_U8_IN_QUEUE_COUNT, | ||
172 | SKL_TKN_U8_OUT_QUEUE_COUNT, | ||
173 | SKL_TKN_U8_TIME_SLOT, | ||
174 | SKL_TKN_U8_CORE_ID, | ||
175 | SKL_TKN_U8_MOD_TYPE, | ||
176 | SKL_TKN_U8_CONN_TYPE, | ||
177 | SKL_TKN_U8_DEV_TYPE, | ||
178 | SKL_TKN_U8_HW_CONN_TYPE, | ||
179 | SKL_TKN_U16_MOD_INST_ID, | ||
180 | SKL_TKN_U16_BLOCK_SIZE, | ||
181 | SKL_TKN_U32_MAX_MCPS, | ||
182 | SKL_TKN_U32_MEM_PAGES, | ||
183 | SKL_TKN_U32_OBS, | ||
184 | SKL_TKN_U32_IBS, | ||
185 | SKL_TKN_U32_VBUS_ID, | ||
186 | SKL_TKN_U32_PARAMS_FIXUP, | ||
187 | SKL_TKN_U32_CONVERTER, | ||
188 | SKL_TKN_U32_PIPE_ID, | ||
189 | SKL_TKN_U32_PIPE_CONN_TYPE, | ||
190 | SKL_TKN_U32_PIPE_PRIORITY, | ||
191 | SKL_TKN_U32_PIPE_MEM_PGS, | ||
192 | SKL_TKN_U32_DIR_PIN_COUNT, | ||
193 | SKL_TKN_U32_FMT_CH, | ||
194 | SKL_TKN_U32_FMT_FREQ, | ||
195 | SKL_TKN_U32_FMT_BIT_DEPTH, | ||
196 | SKL_TKN_U32_FMT_SAMPLE_SIZE, | ||
197 | SKL_TKN_U32_FMT_CH_CONFIG, | ||
198 | SKL_TKN_U32_FMT_INTERLEAVE, | ||
199 | SKL_TKN_U32_FMT_SAMPLE_TYPE, | ||
200 | SKL_TKN_U32_FMT_CH_MAP, | ||
201 | SKL_TKN_U32_PIN_MOD_ID, | ||
202 | SKL_TKN_U32_PIN_INST_ID, | ||
203 | SKL_TKN_U32_MOD_SET_PARAMS, | ||
204 | SKL_TKN_U32_MOD_PARAM_ID, | ||
205 | SKL_TKN_U32_CAPS_SET_PARAMS, | ||
206 | SKL_TKN_U32_CAPS_PARAMS_ID, | ||
207 | SKL_TKN_U32_CAPS_SIZE, | ||
208 | SKL_TKN_U32_PROC_DOMAIN, | ||
209 | SKL_TKN_U32_LIB_COUNT, | ||
210 | SKL_TKN_STR_LIB_NAME, | ||
211 | SKL_TKN_MAX = SKL_TKN_STR_LIB_NAME, | ||
212 | }; | ||
213 | |||
214 | #endif | ||
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 860f8cad6602..261469188566 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c | |||
@@ -29,81 +29,6 @@ | |||
29 | */ | 29 | */ |
30 | #define HDAC_MAX_CAPS 10 | 30 | #define HDAC_MAX_CAPS 10 |
31 | 31 | ||
32 | /** | ||
33 | * snd_hdac_ext_bus_parse_capabilities - parse capablity structure | ||
34 | * @ebus: the pointer to extended bus object | ||
35 | * | ||
36 | * Returns 0 if successful, or a negative error code. | ||
37 | */ | ||
38 | int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *ebus) | ||
39 | { | ||
40 | unsigned int cur_cap; | ||
41 | unsigned int offset; | ||
42 | struct hdac_bus *bus = &ebus->bus; | ||
43 | unsigned int counter = 0; | ||
44 | |||
45 | offset = snd_hdac_chip_readl(bus, LLCH); | ||
46 | |||
47 | /* Lets walk the linked capabilities list */ | ||
48 | do { | ||
49 | cur_cap = _snd_hdac_chip_read(l, bus, offset); | ||
50 | |||
51 | dev_dbg(bus->dev, "Capability version: 0x%x\n", | ||
52 | ((cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF)); | ||
53 | |||
54 | dev_dbg(bus->dev, "HDA capability ID: 0x%x\n", | ||
55 | (cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF); | ||
56 | |||
57 | switch ((cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF) { | ||
58 | case AZX_ML_CAP_ID: | ||
59 | dev_dbg(bus->dev, "Found ML capability\n"); | ||
60 | ebus->mlcap = bus->remap_addr + offset; | ||
61 | break; | ||
62 | |||
63 | case AZX_GTS_CAP_ID: | ||
64 | dev_dbg(bus->dev, "Found GTS capability offset=%x\n", offset); | ||
65 | ebus->gtscap = bus->remap_addr + offset; | ||
66 | break; | ||
67 | |||
68 | case AZX_PP_CAP_ID: | ||
69 | /* PP capability found, the Audio DSP is present */ | ||
70 | dev_dbg(bus->dev, "Found PP capability offset=%x\n", offset); | ||
71 | ebus->ppcap = bus->remap_addr + offset; | ||
72 | break; | ||
73 | |||
74 | case AZX_SPB_CAP_ID: | ||
75 | /* SPIB capability found, handler function */ | ||
76 | dev_dbg(bus->dev, "Found SPB capability\n"); | ||
77 | ebus->spbcap = bus->remap_addr + offset; | ||
78 | break; | ||
79 | |||
80 | case AZX_DRSM_CAP_ID: | ||
81 | /* DMA resume capability found, handler function */ | ||
82 | dev_dbg(bus->dev, "Found DRSM capability\n"); | ||
83 | ebus->drsmcap = bus->remap_addr + offset; | ||
84 | break; | ||
85 | |||
86 | default: | ||
87 | dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap); | ||
88 | break; | ||
89 | } | ||
90 | |||
91 | counter++; | ||
92 | |||
93 | if (counter > HDAC_MAX_CAPS) { | ||
94 | dev_err(bus->dev, "We exceeded HDAC Ext capablities!!!\n"); | ||
95 | break; | ||
96 | } | ||
97 | |||
98 | /* read the offset of next capabiity */ | ||
99 | offset = cur_cap & AZX_CAP_HDR_NXT_PTR_MASK; | ||
100 | |||
101 | } while (offset); | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_parse_capabilities); | ||
106 | |||
107 | /* | 32 | /* |
108 | * processing pipe helpers - these helpers are useful for dealing with HDA | 33 | * processing pipe helpers - these helpers are useful for dealing with HDA |
109 | * new capability of processing pipelines | 34 | * new capability of processing pipelines |
@@ -118,15 +43,15 @@ void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *ebus, bool enable) | |||
118 | { | 43 | { |
119 | struct hdac_bus *bus = &ebus->bus; | 44 | struct hdac_bus *bus = &ebus->bus; |
120 | 45 | ||
121 | if (!ebus->ppcap) { | 46 | if (!bus->ppcap) { |
122 | dev_err(bus->dev, "Address of PP capability is NULL"); | 47 | dev_err(bus->dev, "Address of PP capability is NULL"); |
123 | return; | 48 | return; |
124 | } | 49 | } |
125 | 50 | ||
126 | if (enable) | 51 | if (enable) |
127 | snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN); | 52 | snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN); |
128 | else | 53 | else |
129 | snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0); | 54 | snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0); |
130 | } | 55 | } |
131 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable); | 56 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable); |
132 | 57 | ||
@@ -139,15 +64,15 @@ void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *ebus, bool enable) | |||
139 | { | 64 | { |
140 | struct hdac_bus *bus = &ebus->bus; | 65 | struct hdac_bus *bus = &ebus->bus; |
141 | 66 | ||
142 | if (!ebus->ppcap) { | 67 | if (!bus->ppcap) { |
143 | dev_err(bus->dev, "Address of PP capability is NULL\n"); | 68 | dev_err(bus->dev, "Address of PP capability is NULL\n"); |
144 | return; | 69 | return; |
145 | } | 70 | } |
146 | 71 | ||
147 | if (enable) | 72 | if (enable) |
148 | snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE); | 73 | snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE); |
149 | else | 74 | else |
150 | snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0); | 75 | snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0); |
151 | } | 76 | } |
152 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable); | 77 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable); |
153 | 78 | ||
@@ -171,7 +96,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus) | |||
171 | struct hdac_ext_link *hlink; | 96 | struct hdac_ext_link *hlink; |
172 | struct hdac_bus *bus = &ebus->bus; | 97 | struct hdac_bus *bus = &ebus->bus; |
173 | 98 | ||
174 | link_count = readl(ebus->mlcap + AZX_REG_ML_MLCD) + 1; | 99 | link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1; |
175 | 100 | ||
176 | dev_dbg(bus->dev, "In %s Link count: %d\n", __func__, link_count); | 101 | dev_dbg(bus->dev, "In %s Link count: %d\n", __func__, link_count); |
177 | 102 | ||
@@ -181,7 +106,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus) | |||
181 | return -ENOMEM; | 106 | return -ENOMEM; |
182 | hlink->index = idx; | 107 | hlink->index = idx; |
183 | hlink->bus = bus; | 108 | hlink->bus = bus; |
184 | hlink->ml_addr = ebus->mlcap + AZX_ML_BASE + | 109 | hlink->ml_addr = bus->mlcap + AZX_ML_BASE + |
185 | (AZX_ML_INTERVAL * idx); | 110 | (AZX_ML_INTERVAL * idx); |
186 | hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP); | 111 | hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP); |
187 | hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID); | 112 | hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID); |
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index 626f3bb24c55..2441273adcef 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c | |||
@@ -40,27 +40,27 @@ void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus, | |||
40 | { | 40 | { |
41 | struct hdac_bus *bus = &ebus->bus; | 41 | struct hdac_bus *bus = &ebus->bus; |
42 | 42 | ||
43 | if (ebus->ppcap) { | 43 | if (bus->ppcap) { |
44 | stream->pphc_addr = ebus->ppcap + AZX_PPHC_BASE + | 44 | stream->pphc_addr = bus->ppcap + AZX_PPHC_BASE + |
45 | AZX_PPHC_INTERVAL * idx; | 45 | AZX_PPHC_INTERVAL * idx; |
46 | 46 | ||
47 | stream->pplc_addr = ebus->ppcap + AZX_PPLC_BASE + | 47 | stream->pplc_addr = bus->ppcap + AZX_PPLC_BASE + |
48 | AZX_PPLC_MULTI * ebus->num_streams + | 48 | AZX_PPLC_MULTI * ebus->num_streams + |
49 | AZX_PPLC_INTERVAL * idx; | 49 | AZX_PPLC_INTERVAL * idx; |
50 | } | 50 | } |
51 | 51 | ||
52 | if (ebus->spbcap) { | 52 | if (bus->spbcap) { |
53 | stream->spib_addr = ebus->spbcap + AZX_SPB_BASE + | 53 | stream->spib_addr = bus->spbcap + AZX_SPB_BASE + |
54 | AZX_SPB_INTERVAL * idx + | 54 | AZX_SPB_INTERVAL * idx + |
55 | AZX_SPB_SPIB; | 55 | AZX_SPB_SPIB; |
56 | 56 | ||
57 | stream->fifo_addr = ebus->spbcap + AZX_SPB_BASE + | 57 | stream->fifo_addr = bus->spbcap + AZX_SPB_BASE + |
58 | AZX_SPB_INTERVAL * idx + | 58 | AZX_SPB_INTERVAL * idx + |
59 | AZX_SPB_MAXFIFO; | 59 | AZX_SPB_MAXFIFO; |
60 | } | 60 | } |
61 | 61 | ||
62 | if (ebus->drsmcap) | 62 | if (bus->drsmcap) |
63 | stream->dpibr_addr = ebus->drsmcap + AZX_DRSM_BASE + | 63 | stream->dpibr_addr = bus->drsmcap + AZX_DRSM_BASE + |
64 | AZX_DRSM_INTERVAL * idx; | 64 | AZX_DRSM_INTERVAL * idx; |
65 | 65 | ||
66 | stream->decoupled = false; | 66 | stream->decoupled = false; |
@@ -131,10 +131,10 @@ void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus, | |||
131 | 131 | ||
132 | spin_lock_irq(&bus->reg_lock); | 132 | spin_lock_irq(&bus->reg_lock); |
133 | if (decouple) | 133 | if (decouple) |
134 | snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, 0, | 134 | snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, |
135 | AZX_PPCTL_PROCEN(hstream->index)); | 135 | AZX_PPCTL_PROCEN(hstream->index)); |
136 | else | 136 | else |
137 | snd_hdac_updatel(ebus->ppcap, AZX_REG_PP_PPCTL, | 137 | snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, |
138 | AZX_PPCTL_PROCEN(hstream->index), 0); | 138 | AZX_PPCTL_PROCEN(hstream->index), 0); |
139 | stream->decoupled = decouple; | 139 | stream->decoupled = decouple; |
140 | spin_unlock_irq(&bus->reg_lock); | 140 | spin_unlock_irq(&bus->reg_lock); |
@@ -255,7 +255,7 @@ hdac_ext_link_stream_assign(struct hdac_ext_bus *ebus, | |||
255 | struct hdac_stream *stream = NULL; | 255 | struct hdac_stream *stream = NULL; |
256 | struct hdac_bus *hbus = &ebus->bus; | 256 | struct hdac_bus *hbus = &ebus->bus; |
257 | 257 | ||
258 | if (!ebus->ppcap) { | 258 | if (!hbus->ppcap) { |
259 | dev_err(hbus->dev, "stream type not supported\n"); | 259 | dev_err(hbus->dev, "stream type not supported\n"); |
260 | return NULL; | 260 | return NULL; |
261 | } | 261 | } |
@@ -296,7 +296,7 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus, | |||
296 | struct hdac_stream *stream = NULL; | 296 | struct hdac_stream *stream = NULL; |
297 | struct hdac_bus *hbus = &ebus->bus; | 297 | struct hdac_bus *hbus = &ebus->bus; |
298 | 298 | ||
299 | if (!ebus->ppcap) { | 299 | if (!hbus->ppcap) { |
300 | dev_err(hbus->dev, "stream type not supported\n"); | 300 | dev_err(hbus->dev, "stream type not supported\n"); |
301 | return NULL; | 301 | return NULL; |
302 | } | 302 | } |
@@ -423,21 +423,21 @@ void snd_hdac_ext_stream_spbcap_enable(struct hdac_ext_bus *ebus, | |||
423 | u32 register_mask = 0; | 423 | u32 register_mask = 0; |
424 | struct hdac_bus *bus = &ebus->bus; | 424 | struct hdac_bus *bus = &ebus->bus; |
425 | 425 | ||
426 | if (!ebus->spbcap) { | 426 | if (!bus->spbcap) { |
427 | dev_err(bus->dev, "Address of SPB capability is NULL"); | 427 | dev_err(bus->dev, "Address of SPB capability is NULL"); |
428 | return; | 428 | return; |
429 | } | 429 | } |
430 | 430 | ||
431 | mask |= (1 << index); | 431 | mask |= (1 << index); |
432 | 432 | ||
433 | register_mask = readl(ebus->spbcap + AZX_REG_SPB_SPBFCCTL); | 433 | register_mask = readl(bus->spbcap + AZX_REG_SPB_SPBFCCTL); |
434 | 434 | ||
435 | mask |= register_mask; | 435 | mask |= register_mask; |
436 | 436 | ||
437 | if (enable) | 437 | if (enable) |
438 | snd_hdac_updatel(ebus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask); | 438 | snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask); |
439 | else | 439 | else |
440 | snd_hdac_updatel(ebus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0); | 440 | snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0); |
441 | } | 441 | } |
442 | EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable); | 442 | EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable); |
443 | 443 | ||
@@ -452,7 +452,7 @@ int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus, | |||
452 | { | 452 | { |
453 | struct hdac_bus *bus = &ebus->bus; | 453 | struct hdac_bus *bus = &ebus->bus; |
454 | 454 | ||
455 | if (!ebus->spbcap) { | 455 | if (!bus->spbcap) { |
456 | dev_err(bus->dev, "Address of SPB capability is NULL"); | 456 | dev_err(bus->dev, "Address of SPB capability is NULL"); |
457 | return -EINVAL; | 457 | return -EINVAL; |
458 | } | 458 | } |
@@ -475,7 +475,7 @@ int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus, | |||
475 | { | 475 | { |
476 | struct hdac_bus *bus = &ebus->bus; | 476 | struct hdac_bus *bus = &ebus->bus; |
477 | 477 | ||
478 | if (!ebus->spbcap) { | 478 | if (!bus->spbcap) { |
479 | dev_err(bus->dev, "Address of SPB capability is NULL"); | 479 | dev_err(bus->dev, "Address of SPB capability is NULL"); |
480 | return -EINVAL; | 480 | return -EINVAL; |
481 | } | 481 | } |
@@ -515,21 +515,21 @@ void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus, | |||
515 | u32 register_mask = 0; | 515 | u32 register_mask = 0; |
516 | struct hdac_bus *bus = &ebus->bus; | 516 | struct hdac_bus *bus = &ebus->bus; |
517 | 517 | ||
518 | if (!ebus->drsmcap) { | 518 | if (!bus->drsmcap) { |
519 | dev_err(bus->dev, "Address of DRSM capability is NULL"); | 519 | dev_err(bus->dev, "Address of DRSM capability is NULL"); |
520 | return; | 520 | return; |
521 | } | 521 | } |
522 | 522 | ||
523 | mask |= (1 << index); | 523 | mask |= (1 << index); |
524 | 524 | ||
525 | register_mask = readl(ebus->drsmcap + AZX_REG_SPB_SPBFCCTL); | 525 | register_mask = readl(bus->drsmcap + AZX_REG_SPB_SPBFCCTL); |
526 | 526 | ||
527 | mask |= register_mask; | 527 | mask |= register_mask; |
528 | 528 | ||
529 | if (enable) | 529 | if (enable) |
530 | snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, 0, mask); | 530 | snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, 0, mask); |
531 | else | 531 | else |
532 | snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, mask, 0); | 532 | snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0); |
533 | } | 533 | } |
534 | EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable); | 534 | EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable); |
535 | 535 | ||
@@ -544,7 +544,7 @@ int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus, | |||
544 | { | 544 | { |
545 | struct hdac_bus *bus = &ebus->bus; | 545 | struct hdac_bus *bus = &ebus->bus; |
546 | 546 | ||
547 | if (!ebus->drsmcap) { | 547 | if (!bus->drsmcap) { |
548 | dev_err(bus->dev, "Address of DRSM capability is NULL"); | 548 | dev_err(bus->dev, "Address of DRSM capability is NULL"); |
549 | return -EINVAL; | 549 | return -EINVAL; |
550 | } | 550 | } |
diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index 9fee464e5d49..043065867656 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c | |||
@@ -255,6 +255,81 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, | |||
255 | } | 255 | } |
256 | EXPORT_SYMBOL_GPL(snd_hdac_bus_get_response); | 256 | EXPORT_SYMBOL_GPL(snd_hdac_bus_get_response); |
257 | 257 | ||
258 | #define HDAC_MAX_CAPS 10 | ||
259 | /** | ||
260 | * snd_hdac_bus_parse_capabilities - parse capability structure | ||
261 | * @bus: the pointer to bus object | ||
262 | * | ||
263 | * Returns 0 if successful, or a negative error code. | ||
264 | */ | ||
265 | int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus) | ||
266 | { | ||
267 | unsigned int cur_cap; | ||
268 | unsigned int offset; | ||
269 | unsigned int counter = 0; | ||
270 | |||
271 | offset = snd_hdac_chip_readl(bus, LLCH); | ||
272 | |||
273 | /* Lets walk the linked capabilities list */ | ||
274 | do { | ||
275 | cur_cap = _snd_hdac_chip_read(l, bus, offset); | ||
276 | |||
277 | dev_dbg(bus->dev, "Capability version: 0x%x\n", | ||
278 | (cur_cap & AZX_CAP_HDR_VER_MASK) >> AZX_CAP_HDR_VER_OFF); | ||
279 | |||
280 | dev_dbg(bus->dev, "HDA capability ID: 0x%x\n", | ||
281 | (cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF); | ||
282 | |||
283 | switch ((cur_cap & AZX_CAP_HDR_ID_MASK) >> AZX_CAP_HDR_ID_OFF) { | ||
284 | case AZX_ML_CAP_ID: | ||
285 | dev_dbg(bus->dev, "Found ML capability\n"); | ||
286 | bus->mlcap = bus->remap_addr + offset; | ||
287 | break; | ||
288 | |||
289 | case AZX_GTS_CAP_ID: | ||
290 | dev_dbg(bus->dev, "Found GTS capability offset=%x\n", offset); | ||
291 | bus->gtscap = bus->remap_addr + offset; | ||
292 | break; | ||
293 | |||
294 | case AZX_PP_CAP_ID: | ||
295 | /* PP capability found, the Audio DSP is present */ | ||
296 | dev_dbg(bus->dev, "Found PP capability offset=%x\n", offset); | ||
297 | bus->ppcap = bus->remap_addr + offset; | ||
298 | break; | ||
299 | |||
300 | case AZX_SPB_CAP_ID: | ||
301 | /* SPIB capability found, handler function */ | ||
302 | dev_dbg(bus->dev, "Found SPB capability\n"); | ||
303 | bus->spbcap = bus->remap_addr + offset; | ||
304 | break; | ||
305 | |||
306 | case AZX_DRSM_CAP_ID: | ||
307 | /* DMA resume capability found, handler function */ | ||
308 | dev_dbg(bus->dev, "Found DRSM capability\n"); | ||
309 | bus->drsmcap = bus->remap_addr + offset; | ||
310 | break; | ||
311 | |||
312 | default: | ||
313 | dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap); | ||
314 | break; | ||
315 | } | ||
316 | |||
317 | counter++; | ||
318 | |||
319 | if (counter > HDAC_MAX_CAPS) { | ||
320 | dev_err(bus->dev, "We exceeded HDAC capabilities!!!\n"); | ||
321 | break; | ||
322 | } | ||
323 | |||
324 | /* read the offset of next capability */ | ||
325 | offset = cur_cap & AZX_CAP_HDR_NXT_PTR_MASK; | ||
326 | |||
327 | } while (offset); | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | EXPORT_SYMBOL_GPL(snd_hdac_bus_parse_capabilities); | ||
332 | |||
258 | /* | 333 | /* |
259 | * Lowlevel interface | 334 | * Lowlevel interface |
260 | */ | 335 | */ |
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 27de8015717d..2ad3b447483f 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c | |||
@@ -27,6 +27,12 @@ | |||
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/pm_runtime.h> | 28 | #include <linux/pm_runtime.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | |||
31 | #ifdef CONFIG_X86 | ||
32 | /* for art-tsc conversion */ | ||
33 | #include <asm/tsc.h> | ||
34 | #endif | ||
35 | |||
30 | #include <sound/core.h> | 36 | #include <sound/core.h> |
31 | #include <sound/initval.h> | 37 | #include <sound/initval.h> |
32 | #include "hda_controller.h" | 38 | #include "hda_controller.h" |
@@ -337,12 +343,173 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) | |||
337 | azx_get_position(chip, azx_dev)); | 343 | azx_get_position(chip, azx_dev)); |
338 | } | 344 | } |
339 | 345 | ||
346 | /* | ||
347 | * azx_scale64: Scale base by mult/div while not overflowing sanely | ||
348 | * | ||
349 | * Derived from scale64_check_overflow in kernel/time/timekeeping.c | ||
350 | * | ||
351 | * The tmestamps for a 48Khz stream can overflow after (2^64/10^9)/48K which | ||
352 | * is about 384307 ie ~4.5 days. | ||
353 | * | ||
354 | * This scales the calculation so that overflow will happen but after 2^64 / | ||
355 | * 48000 secs, which is pretty large! | ||
356 | * | ||
357 | * In caln below: | ||
358 | * base may overflow, but since there isn’t any additional division | ||
359 | * performed on base it’s OK | ||
360 | * rem can’t overflow because both are 32-bit values | ||
361 | */ | ||
362 | |||
363 | #ifdef CONFIG_X86 | ||
364 | static u64 azx_scale64(u64 base, u32 num, u32 den) | ||
365 | { | ||
366 | u64 rem; | ||
367 | |||
368 | rem = do_div(base, den); | ||
369 | |||
370 | base *= num; | ||
371 | rem *= num; | ||
372 | |||
373 | do_div(rem, den); | ||
374 | |||
375 | return base + rem; | ||
376 | } | ||
377 | |||
378 | static int azx_get_sync_time(ktime_t *device, | ||
379 | struct system_counterval_t *system, void *ctx) | ||
380 | { | ||
381 | struct snd_pcm_substream *substream = ctx; | ||
382 | struct azx_dev *azx_dev = get_azx_dev(substream); | ||
383 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
384 | struct azx *chip = apcm->chip; | ||
385 | struct snd_pcm_runtime *runtime; | ||
386 | u64 ll_counter, ll_counter_l, ll_counter_h; | ||
387 | u64 tsc_counter, tsc_counter_l, tsc_counter_h; | ||
388 | u32 wallclk_ctr, wallclk_cycles; | ||
389 | bool direction; | ||
390 | u32 dma_select; | ||
391 | u32 timeout = 200; | ||
392 | u32 retry_count = 0; | ||
393 | |||
394 | runtime = substream->runtime; | ||
395 | |||
396 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
397 | direction = 1; | ||
398 | else | ||
399 | direction = 0; | ||
400 | |||
401 | /* 0th stream tag is not used, so DMA ch 0 is for 1st stream tag */ | ||
402 | do { | ||
403 | timeout = 100; | ||
404 | dma_select = (direction << GTSCC_CDMAS_DMA_DIR_SHIFT) | | ||
405 | (azx_dev->core.stream_tag - 1); | ||
406 | snd_hdac_chip_writel(azx_bus(chip), GTSCC, dma_select); | ||
407 | |||
408 | /* Enable the capture */ | ||
409 | snd_hdac_chip_updatel(azx_bus(chip), GTSCC, 0, GTSCC_TSCCI_MASK); | ||
410 | |||
411 | while (timeout) { | ||
412 | if (snd_hdac_chip_readl(azx_bus(chip), GTSCC) & | ||
413 | GTSCC_TSCCD_MASK) | ||
414 | break; | ||
415 | |||
416 | timeout--; | ||
417 | } | ||
418 | |||
419 | if (!timeout) { | ||
420 | dev_err(chip->card->dev, "GTSCC capture Timedout!\n"); | ||
421 | return -EIO; | ||
422 | } | ||
423 | |||
424 | /* Read wall clock counter */ | ||
425 | wallclk_ctr = snd_hdac_chip_readl(azx_bus(chip), WALFCC); | ||
426 | |||
427 | /* Read TSC counter */ | ||
428 | tsc_counter_l = snd_hdac_chip_readl(azx_bus(chip), TSCCL); | ||
429 | tsc_counter_h = snd_hdac_chip_readl(azx_bus(chip), TSCCU); | ||
430 | |||
431 | /* Read Link counter */ | ||
432 | ll_counter_l = snd_hdac_chip_readl(azx_bus(chip), LLPCL); | ||
433 | ll_counter_h = snd_hdac_chip_readl(azx_bus(chip), LLPCU); | ||
434 | |||
435 | /* Ack: registers read done */ | ||
436 | snd_hdac_chip_writel(azx_bus(chip), GTSCC, GTSCC_TSCCD_SHIFT); | ||
437 | |||
438 | tsc_counter = (tsc_counter_h << TSCCU_CCU_SHIFT) | | ||
439 | tsc_counter_l; | ||
440 | |||
441 | ll_counter = (ll_counter_h << LLPC_CCU_SHIFT) | ll_counter_l; | ||
442 | wallclk_cycles = wallclk_ctr & WALFCC_CIF_MASK; | ||
443 | |||
444 | /* | ||
445 | * An error occurs near frame "rollover". The clocks in | ||
446 | * frame value indicates whether this error may have | ||
447 | * occurred. Here we use the value of 10 i.e., | ||
448 | * HDA_MAX_CYCLE_OFFSET | ||
449 | */ | ||
450 | if (wallclk_cycles < HDA_MAX_CYCLE_VALUE - HDA_MAX_CYCLE_OFFSET | ||
451 | && wallclk_cycles > HDA_MAX_CYCLE_OFFSET) | ||
452 | break; | ||
453 | |||
454 | /* | ||
455 | * Sleep before we read again, else we may again get | ||
456 | * value near to MAX_CYCLE. Try to sleep for different | ||
457 | * amount of time so we dont hit the same number again | ||
458 | */ | ||
459 | udelay(retry_count++); | ||
460 | |||
461 | } while (retry_count != HDA_MAX_CYCLE_READ_RETRY); | ||
462 | |||
463 | if (retry_count == HDA_MAX_CYCLE_READ_RETRY) { | ||
464 | dev_err_ratelimited(chip->card->dev, | ||
465 | "Error in WALFCC cycle count\n"); | ||
466 | return -EIO; | ||
467 | } | ||
468 | |||
469 | *device = ns_to_ktime(azx_scale64(ll_counter, | ||
470 | NSEC_PER_SEC, runtime->rate)); | ||
471 | *device = ktime_add_ns(*device, (wallclk_cycles * NSEC_PER_SEC) / | ||
472 | ((HDA_MAX_CYCLE_VALUE + 1) * runtime->rate)); | ||
473 | |||
474 | *system = convert_art_to_tsc(tsc_counter); | ||
475 | |||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | #else | ||
480 | static int azx_get_sync_time(ktime_t *device, | ||
481 | struct system_counterval_t *system, void *ctx) | ||
482 | { | ||
483 | return -ENXIO; | ||
484 | } | ||
485 | #endif | ||
486 | |||
487 | static int azx_get_crosststamp(struct snd_pcm_substream *substream, | ||
488 | struct system_device_crosststamp *xtstamp) | ||
489 | { | ||
490 | return get_device_system_crosststamp(azx_get_sync_time, | ||
491 | substream, NULL, xtstamp); | ||
492 | } | ||
493 | |||
494 | static inline bool is_link_time_supported(struct snd_pcm_runtime *runtime, | ||
495 | struct snd_pcm_audio_tstamp_config *ts) | ||
496 | { | ||
497 | if (runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME) | ||
498 | if (ts->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED) | ||
499 | return true; | ||
500 | |||
501 | return false; | ||
502 | } | ||
503 | |||
340 | static int azx_get_time_info(struct snd_pcm_substream *substream, | 504 | static int azx_get_time_info(struct snd_pcm_substream *substream, |
341 | struct timespec *system_ts, struct timespec *audio_ts, | 505 | struct timespec *system_ts, struct timespec *audio_ts, |
342 | struct snd_pcm_audio_tstamp_config *audio_tstamp_config, | 506 | struct snd_pcm_audio_tstamp_config *audio_tstamp_config, |
343 | struct snd_pcm_audio_tstamp_report *audio_tstamp_report) | 507 | struct snd_pcm_audio_tstamp_report *audio_tstamp_report) |
344 | { | 508 | { |
345 | struct azx_dev *azx_dev = get_azx_dev(substream); | 509 | struct azx_dev *azx_dev = get_azx_dev(substream); |
510 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
511 | struct system_device_crosststamp xtstamp; | ||
512 | int ret; | ||
346 | u64 nsec; | 513 | u64 nsec; |
347 | 514 | ||
348 | if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) && | 515 | if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) && |
@@ -361,8 +528,37 @@ static int azx_get_time_info(struct snd_pcm_substream *substream, | |||
361 | audio_tstamp_report->accuracy_report = 1; /* rest of structure is valid */ | 528 | audio_tstamp_report->accuracy_report = 1; /* rest of structure is valid */ |
362 | audio_tstamp_report->accuracy = 42; /* 24 MHz WallClock == 42ns resolution */ | 529 | audio_tstamp_report->accuracy = 42; /* 24 MHz WallClock == 42ns resolution */ |
363 | 530 | ||
364 | } else | 531 | } else if (is_link_time_supported(runtime, audio_tstamp_config)) { |
532 | |||
533 | ret = azx_get_crosststamp(substream, &xtstamp); | ||
534 | if (ret) | ||
535 | return ret; | ||
536 | |||
537 | switch (runtime->tstamp_type) { | ||
538 | case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC: | ||
539 | return -EINVAL; | ||
540 | |||
541 | case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW: | ||
542 | *system_ts = ktime_to_timespec(xtstamp.sys_monoraw); | ||
543 | break; | ||
544 | |||
545 | default: | ||
546 | *system_ts = ktime_to_timespec(xtstamp.sys_realtime); | ||
547 | break; | ||
548 | |||
549 | } | ||
550 | |||
551 | *audio_ts = ktime_to_timespec(xtstamp.device); | ||
552 | |||
553 | audio_tstamp_report->actual_type = | ||
554 | SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED; | ||
555 | audio_tstamp_report->accuracy_report = 1; | ||
556 | /* 24 MHz WallClock == 42ns resolution */ | ||
557 | audio_tstamp_report->accuracy = 42; | ||
558 | |||
559 | } else { | ||
365 | audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; | 560 | audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; |
561 | } | ||
366 | 562 | ||
367 | return 0; | 563 | return 0; |
368 | } | 564 | } |
@@ -412,6 +608,11 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) | |||
412 | goto unlock; | 608 | goto unlock; |
413 | } | 609 | } |
414 | runtime->private_data = azx_dev; | 610 | runtime->private_data = azx_dev; |
611 | |||
612 | if (chip->gts_present) | ||
613 | azx_pcm_hw.info = azx_pcm_hw.info | | ||
614 | SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME; | ||
615 | |||
415 | runtime->hw = azx_pcm_hw; | 616 | runtime->hw = azx_pcm_hw; |
416 | runtime->hw.channels_min = hinfo->channels_min; | 617 | runtime->hw.channels_min = hinfo->channels_min; |
417 | runtime->hw.channels_max = hinfo->channels_max; | 618 | runtime->hw.channels_max = hinfo->channels_max; |
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index ec63bbf1ec6d..a50e0532622a 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h | |||
@@ -159,6 +159,9 @@ struct azx { | |||
159 | unsigned int region_requested:1; | 159 | unsigned int region_requested:1; |
160 | unsigned int disabled:1; /* disabled by vga_switcheroo */ | 160 | unsigned int disabled:1; /* disabled by vga_switcheroo */ |
161 | 161 | ||
162 | /* GTS present */ | ||
163 | unsigned int gts_present:1; | ||
164 | |||
162 | #ifdef CONFIG_SND_HDA_DSP_LOADER | 165 | #ifdef CONFIG_SND_HDA_DSP_LOADER |
163 | struct azx_dev saved_azx_dev; | 166 | struct azx_dev saved_azx_dev; |
164 | #endif | 167 | #endif |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 160c7f713722..c3469f756ec2 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -54,6 +54,7 @@ | |||
54 | /* for snoop control */ | 54 | /* for snoop control */ |
55 | #include <asm/pgtable.h> | 55 | #include <asm/pgtable.h> |
56 | #include <asm/cacheflush.h> | 56 | #include <asm/cacheflush.h> |
57 | #include <asm/cpufeature.h> | ||
57 | #endif | 58 | #endif |
58 | #include <sound/core.h> | 59 | #include <sound/core.h> |
59 | #include <sound/initval.h> | 60 | #include <sound/initval.h> |
@@ -1663,6 +1664,22 @@ static int azx_first_init(struct azx *chip) | |||
1663 | return -ENXIO; | 1664 | return -ENXIO; |
1664 | } | 1665 | } |
1665 | 1666 | ||
1667 | if (IS_SKL_PLUS(pci)) | ||
1668 | snd_hdac_bus_parse_capabilities(bus); | ||
1669 | |||
1670 | /* | ||
1671 | * Some Intel CPUs has always running timer (ART) feature and | ||
1672 | * controller may have Global time sync reporting capability, so | ||
1673 | * check both of these before declaring synchronized time reporting | ||
1674 | * capability SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME | ||
1675 | */ | ||
1676 | chip->gts_present = false; | ||
1677 | |||
1678 | #ifdef CONFIG_X86 | ||
1679 | if (bus->ppcap && boot_cpu_has(X86_FEATURE_ART)) | ||
1680 | chip->gts_present = true; | ||
1681 | #endif | ||
1682 | |||
1666 | if (chip->msi) { | 1683 | if (chip->msi) { |
1667 | if (chip->driver_caps & AZX_DCAPS_NO_MSI64) { | 1684 | if (chip->driver_caps & AZX_DCAPS_NO_MSI64) { |
1668 | dev_dbg(card->dev, "Disabling 64bit MSI\n"); | 1685 | dev_dbg(card->dev, "Disabling 64bit MSI\n"); |
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 09e8988bbb2d..b0f6f0712ba1 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c | |||
@@ -1870,6 +1870,9 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, | |||
1870 | case RT5640_SCLK_S_PLL1: | 1870 | case RT5640_SCLK_S_PLL1: |
1871 | reg_val |= RT5640_SCLK_SRC_PLL1; | 1871 | reg_val |= RT5640_SCLK_SRC_PLL1; |
1872 | break; | 1872 | break; |
1873 | case RT5640_SCLK_S_RCCLK: | ||
1874 | reg_val |= RT5640_SCLK_SRC_RCCLK; | ||
1875 | break; | ||
1873 | default: | 1876 | default: |
1874 | dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); | 1877 | dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); |
1875 | return -EINVAL; | 1878 | return -EINVAL; |
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 58b664b06c16..90c88711c72a 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h | |||
@@ -984,6 +984,7 @@ | |||
984 | #define RT5640_SCLK_SRC_SFT 14 | 984 | #define RT5640_SCLK_SRC_SFT 14 |
985 | #define RT5640_SCLK_SRC_MCLK (0x0 << 14) | 985 | #define RT5640_SCLK_SRC_MCLK (0x0 << 14) |
986 | #define RT5640_SCLK_SRC_PLL1 (0x1 << 14) | 986 | #define RT5640_SCLK_SRC_PLL1 (0x1 << 14) |
987 | #define RT5640_SCLK_SRC_RCCLK (0x2 << 14) | ||
987 | #define RT5640_PLL1_SRC_MASK (0x3 << 12) | 988 | #define RT5640_PLL1_SRC_MASK (0x3 << 12) |
988 | #define RT5640_PLL1_SRC_SFT 12 | 989 | #define RT5640_PLL1_SRC_SFT 12 |
989 | #define RT5640_PLL1_SRC_MCLK (0x0 << 12) | 990 | #define RT5640_PLL1_SRC_MCLK (0x0 << 12) |
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index a20c3dfbcb5d..26eb5a0a5575 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig | |||
@@ -25,6 +25,7 @@ config SND_SST_IPC_ACPI | |||
25 | tristate | 25 | tristate |
26 | select SND_SST_IPC | 26 | select SND_SST_IPC |
27 | select SND_SOC_INTEL_SST | 27 | select SND_SOC_INTEL_SST |
28 | select IOSF_MBI | ||
28 | 29 | ||
29 | config SND_SOC_INTEL_SST | 30 | config SND_SOC_INTEL_SST |
30 | tristate | 31 | tristate |
@@ -120,6 +121,17 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH | |||
120 | This adds audio driver for Intel Baytrail platform based boards | 121 | This adds audio driver for Intel Baytrail platform based boards |
121 | with the MAX98090 audio codec. | 122 | with the MAX98090 audio codec. |
122 | 123 | ||
124 | config SND_SOC_INTEL_BDW_RT5677_MACH | ||
125 | tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec" | ||
126 | depends on X86_INTEL_LPSS && GPIOLIB && I2C && DW_DMAC | ||
127 | depends on DW_DMAC_CORE=y | ||
128 | select SND_SOC_INTEL_SST | ||
129 | select SND_SOC_INTEL_HASWELL | ||
130 | select SND_SOC_RT5677 | ||
131 | help | ||
132 | This adds support for Intel Broadwell platform based boards with | ||
133 | the RT5677 audio codec. | ||
134 | |||
123 | config SND_SOC_INTEL_BROADWELL_MACH | 135 | config SND_SOC_INTEL_BROADWELL_MACH |
124 | tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" | 136 | tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" |
125 | depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ | 137 | depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ |
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 98720a93de8a..0838478c4c3f 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld | 2 | * sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld |
3 | * | 3 | * |
4 | * Copyright (C) 2013-14 Intel Corp | 4 | * Copyright (C) 2013-14 Intel Corp |
@@ -534,6 +534,7 @@ static const DECLARE_TLV_DB_SCALE(sst_gain_tlv_common, SST_GAIN_MIN_VALUE * 10, | |||
534 | 534 | ||
535 | /* Look up table to convert MIXER SW bit regs to SWM inputs */ | 535 | /* Look up table to convert MIXER SW bit regs to SWM inputs */ |
536 | static const uint swm_mixer_input_ids[SST_SWM_INPUT_COUNT] = { | 536 | static const uint swm_mixer_input_ids[SST_SWM_INPUT_COUNT] = { |
537 | [SST_IP_MODEM] = SST_SWM_IN_MODEM, | ||
537 | [SST_IP_CODEC0] = SST_SWM_IN_CODEC0, | 538 | [SST_IP_CODEC0] = SST_SWM_IN_CODEC0, |
538 | [SST_IP_CODEC1] = SST_SWM_IN_CODEC1, | 539 | [SST_IP_CODEC1] = SST_SWM_IN_CODEC1, |
539 | [SST_IP_LOOP0] = SST_SWM_IN_SPROT_LOOP, | 540 | [SST_IP_LOOP0] = SST_SWM_IN_SPROT_LOOP, |
@@ -674,6 +675,7 @@ static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w, | |||
674 | /* SBA mixers - 16 inputs */ | 675 | /* SBA mixers - 16 inputs */ |
675 | #define SST_SBA_DECLARE_MIX_CONTROLS(kctl_name) \ | 676 | #define SST_SBA_DECLARE_MIX_CONTROLS(kctl_name) \ |
676 | static const struct snd_kcontrol_new kctl_name[] = { \ | 677 | static const struct snd_kcontrol_new kctl_name[] = { \ |
678 | SOC_DAPM_SINGLE("modem_in Switch", SND_SOC_NOPM, SST_IP_MODEM, 1, 0), \ | ||
677 | SOC_DAPM_SINGLE("codec_in0 Switch", SND_SOC_NOPM, SST_IP_CODEC0, 1, 0), \ | 679 | SOC_DAPM_SINGLE("codec_in0 Switch", SND_SOC_NOPM, SST_IP_CODEC0, 1, 0), \ |
678 | SOC_DAPM_SINGLE("codec_in1 Switch", SND_SOC_NOPM, SST_IP_CODEC1, 1, 0), \ | 680 | SOC_DAPM_SINGLE("codec_in1 Switch", SND_SOC_NOPM, SST_IP_CODEC1, 1, 0), \ |
679 | SOC_DAPM_SINGLE("sprot_loop_in Switch", SND_SOC_NOPM, SST_IP_LOOP0, 1, 0), \ | 681 | SOC_DAPM_SINGLE("sprot_loop_in Switch", SND_SOC_NOPM, SST_IP_LOOP0, 1, 0), \ |
@@ -684,6 +686,7 @@ static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w, | |||
684 | } | 686 | } |
685 | 687 | ||
686 | #define SST_SBA_MIXER_GRAPH_MAP(mix_name) \ | 688 | #define SST_SBA_MIXER_GRAPH_MAP(mix_name) \ |
689 | { mix_name, "modem_in Switch", "modem_in" }, \ | ||
687 | { mix_name, "codec_in0 Switch", "codec_in0" }, \ | 690 | { mix_name, "codec_in0 Switch", "codec_in0" }, \ |
688 | { mix_name, "codec_in1 Switch", "codec_in1" }, \ | 691 | { mix_name, "codec_in1 Switch", "codec_in1" }, \ |
689 | { mix_name, "sprot_loop_in Switch", "sprot_loop_in" }, \ | 692 | { mix_name, "sprot_loop_in Switch", "sprot_loop_in" }, \ |
@@ -713,6 +716,7 @@ SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l2_controls); | |||
713 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_voip_controls); | 716 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_voip_controls); |
714 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec0_controls); | 717 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec0_controls); |
715 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec1_controls); | 718 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec1_controls); |
719 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_modem_controls); | ||
716 | 720 | ||
717 | /* | 721 | /* |
718 | * sst_handle_vb_timer - Start/Stop the DSP scheduler | 722 | * sst_handle_vb_timer - Start/Stop the DSP scheduler |
@@ -931,17 +935,26 @@ void sst_fill_ssp_defaults(struct snd_soc_dai *dai) | |||
931 | int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) | 935 | int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) |
932 | { | 936 | { |
933 | struct sst_data *drv = snd_soc_dai_get_drvdata(dai); | 937 | struct sst_data *drv = snd_soc_dai_get_drvdata(dai); |
934 | const struct sst_ssp_config *config; | 938 | int ssp_id; |
935 | 939 | ||
936 | dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); | 940 | dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); |
937 | 941 | ||
942 | if (strcmp(id, "ssp0-port") == 0) | ||
943 | ssp_id = SSP_MODEM; | ||
944 | else if (strcmp(id, "ssp2-port") == 0) | ||
945 | ssp_id = SSP_CODEC; | ||
946 | else { | ||
947 | dev_dbg(dai->dev, "port %s is not supported\n", id); | ||
948 | return -1; | ||
949 | } | ||
950 | |||
938 | SST_FILL_DEFAULT_DESTINATION(drv->ssp_cmd.header.dst); | 951 | SST_FILL_DEFAULT_DESTINATION(drv->ssp_cmd.header.dst); |
939 | drv->ssp_cmd.header.command_id = SBA_HW_SET_SSP; | 952 | drv->ssp_cmd.header.command_id = SBA_HW_SET_SSP; |
940 | drv->ssp_cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp) | 953 | drv->ssp_cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp) |
941 | - sizeof(struct sst_dsp_header); | 954 | - sizeof(struct sst_dsp_header); |
942 | 955 | ||
943 | config = &sst_ssp_configs; | 956 | drv->ssp_cmd.selection = ssp_id; |
944 | dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id); | 957 | dev_dbg(dai->dev, "ssp_id: %u\n", ssp_id); |
945 | 958 | ||
946 | if (enable) | 959 | if (enable) |
947 | drv->ssp_cmd.switch_state = SST_SWITCH_ON; | 960 | drv->ssp_cmd.switch_state = SST_SWITCH_ON; |
@@ -1047,8 +1060,10 @@ static int sst_set_media_loop(struct snd_soc_dapm_widget *w, | |||
1047 | } | 1060 | } |
1048 | 1061 | ||
1049 | static const struct snd_soc_dapm_widget sst_dapm_widgets[] = { | 1062 | static const struct snd_soc_dapm_widget sst_dapm_widgets[] = { |
1063 | SST_AIF_IN("modem_in", sst_set_be_modules), | ||
1050 | SST_AIF_IN("codec_in0", sst_set_be_modules), | 1064 | SST_AIF_IN("codec_in0", sst_set_be_modules), |
1051 | SST_AIF_IN("codec_in1", sst_set_be_modules), | 1065 | SST_AIF_IN("codec_in1", sst_set_be_modules), |
1066 | SST_AIF_OUT("modem_out", sst_set_be_modules), | ||
1052 | SST_AIF_OUT("codec_out0", sst_set_be_modules), | 1067 | SST_AIF_OUT("codec_out0", sst_set_be_modules), |
1053 | SST_AIF_OUT("codec_out1", sst_set_be_modules), | 1068 | SST_AIF_OUT("codec_out1", sst_set_be_modules), |
1054 | 1069 | ||
@@ -1103,6 +1118,9 @@ static const struct snd_soc_dapm_widget sst_dapm_widgets[] = { | |||
1103 | sst_mix_codec0_controls, sst_swm_mixer_event), | 1118 | sst_mix_codec0_controls, sst_swm_mixer_event), |
1104 | SST_SWM_MIXER("codec_out1 mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_CODEC1, | 1119 | SST_SWM_MIXER("codec_out1 mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_CODEC1, |
1105 | sst_mix_codec1_controls, sst_swm_mixer_event), | 1120 | sst_mix_codec1_controls, sst_swm_mixer_event), |
1121 | SST_SWM_MIXER("modem_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_MODEM, | ||
1122 | sst_mix_modem_controls, sst_swm_mixer_event), | ||
1123 | |||
1106 | }; | 1124 | }; |
1107 | 1125 | ||
1108 | static const struct snd_soc_dapm_route intercon[] = { | 1126 | static const struct snd_soc_dapm_route intercon[] = { |
@@ -1148,6 +1166,9 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1148 | SST_SBA_MIXER_GRAPH_MAP("codec_out0 mix 0"), | 1166 | SST_SBA_MIXER_GRAPH_MAP("codec_out0 mix 0"), |
1149 | {"codec_out1", NULL, "codec_out1 mix 0"}, | 1167 | {"codec_out1", NULL, "codec_out1 mix 0"}, |
1150 | SST_SBA_MIXER_GRAPH_MAP("codec_out1 mix 0"), | 1168 | SST_SBA_MIXER_GRAPH_MAP("codec_out1 mix 0"), |
1169 | {"modem_out", NULL, "modem_out mix 0"}, | ||
1170 | SST_SBA_MIXER_GRAPH_MAP("modem_out mix 0"), | ||
1171 | |||
1151 | 1172 | ||
1152 | }; | 1173 | }; |
1153 | static const char * const slot_names[] = { | 1174 | static const char * const slot_names[] = { |
@@ -1217,6 +1238,9 @@ static const struct snd_kcontrol_new sst_gain_controls[] = { | |||
1217 | SST_GAIN("media_loop2_out", SST_PATH_INDEX_MEDIA_LOOP2_OUT, SST_TASK_SBA, 0, &sst_gains[13]), | 1238 | SST_GAIN("media_loop2_out", SST_PATH_INDEX_MEDIA_LOOP2_OUT, SST_TASK_SBA, 0, &sst_gains[13]), |
1218 | SST_GAIN("sprot_loop_out", SST_PATH_INDEX_SPROT_LOOP_OUT, SST_TASK_SBA, 0, &sst_gains[14]), | 1239 | SST_GAIN("sprot_loop_out", SST_PATH_INDEX_SPROT_LOOP_OUT, SST_TASK_SBA, 0, &sst_gains[14]), |
1219 | SST_VOLUME("media0_in", SST_PATH_INDEX_MEDIA0_IN, SST_TASK_MMX, 0, &sst_gains[15]), | 1240 | SST_VOLUME("media0_in", SST_PATH_INDEX_MEDIA0_IN, SST_TASK_MMX, 0, &sst_gains[15]), |
1241 | SST_GAIN("modem_in", SST_PATH_INDEX_MODEM_IN, SST_TASK_SBA, 0, &sst_gains[16]), | ||
1242 | SST_GAIN("modem_out", SST_PATH_INDEX_MODEM_OUT, SST_TASK_SBA, 0, &sst_gains[17]), | ||
1243 | |||
1220 | }; | 1244 | }; |
1221 | 1245 | ||
1222 | #define SST_GAIN_NUM_CONTROLS 3 | 1246 | #define SST_GAIN_NUM_CONTROLS 3 |
diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h index e0113112f668..351d81469685 100644 --- a/sound/soc/intel/atom/sst-atom-controls.h +++ b/sound/soc/intel/atom/sst-atom-controls.h | |||
@@ -35,6 +35,8 @@ enum { | |||
35 | /* define a bit for each mixer input */ | 35 | /* define a bit for each mixer input */ |
36 | #define SST_MIX_IP(x) (x) | 36 | #define SST_MIX_IP(x) (x) |
37 | 37 | ||
38 | #define SST_IP_MODEM SST_MIX_IP(0) | ||
39 | #define SST_IP_BT SST_MIX_IP(1) | ||
38 | #define SST_IP_CODEC0 SST_MIX_IP(2) | 40 | #define SST_IP_CODEC0 SST_MIX_IP(2) |
39 | #define SST_IP_CODEC1 SST_MIX_IP(3) | 41 | #define SST_IP_CODEC1 SST_MIX_IP(3) |
40 | #define SST_IP_LOOP0 SST_MIX_IP(4) | 42 | #define SST_IP_LOOP0 SST_MIX_IP(4) |
@@ -63,6 +65,7 @@ enum { | |||
63 | * Audio DSP Path Ids. Specified by the audio DSP FW | 65 | * Audio DSP Path Ids. Specified by the audio DSP FW |
64 | */ | 66 | */ |
65 | enum sst_path_index { | 67 | enum sst_path_index { |
68 | SST_PATH_INDEX_MODEM_OUT = (0x00 << SST_PATH_ID_SHIFT), | ||
66 | SST_PATH_INDEX_CODEC_OUT0 = (0x02 << SST_PATH_ID_SHIFT), | 69 | SST_PATH_INDEX_CODEC_OUT0 = (0x02 << SST_PATH_ID_SHIFT), |
67 | SST_PATH_INDEX_CODEC_OUT1 = (0x03 << SST_PATH_ID_SHIFT), | 70 | SST_PATH_INDEX_CODEC_OUT1 = (0x03 << SST_PATH_ID_SHIFT), |
68 | 71 | ||
@@ -80,6 +83,7 @@ enum sst_path_index { | |||
80 | 83 | ||
81 | 84 | ||
82 | /* Start of input paths */ | 85 | /* Start of input paths */ |
86 | SST_PATH_INDEX_MODEM_IN = (0x80 << SST_PATH_ID_SHIFT), | ||
83 | SST_PATH_INDEX_CODEC_IN0 = (0x82 << SST_PATH_ID_SHIFT), | 87 | SST_PATH_INDEX_CODEC_IN0 = (0x82 << SST_PATH_ID_SHIFT), |
84 | SST_PATH_INDEX_CODEC_IN1 = (0x83 << SST_PATH_ID_SHIFT), | 88 | SST_PATH_INDEX_CODEC_IN1 = (0x83 << SST_PATH_ID_SHIFT), |
85 | 89 | ||
@@ -105,6 +109,7 @@ enum sst_path_index { | |||
105 | * path IDs | 109 | * path IDs |
106 | */ | 110 | */ |
107 | enum sst_swm_inputs { | 111 | enum sst_swm_inputs { |
112 | SST_SWM_IN_MODEM = (SST_PATH_INDEX_MODEM_IN | SST_DEFAULT_CELL_NBR), | ||
108 | SST_SWM_IN_CODEC0 = (SST_PATH_INDEX_CODEC_IN0 | SST_DEFAULT_CELL_NBR), | 113 | SST_SWM_IN_CODEC0 = (SST_PATH_INDEX_CODEC_IN0 | SST_DEFAULT_CELL_NBR), |
109 | SST_SWM_IN_CODEC1 = (SST_PATH_INDEX_CODEC_IN1 | SST_DEFAULT_CELL_NBR), | 114 | SST_SWM_IN_CODEC1 = (SST_PATH_INDEX_CODEC_IN1 | SST_DEFAULT_CELL_NBR), |
110 | SST_SWM_IN_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_IN | SST_DEFAULT_CELL_NBR), | 115 | SST_SWM_IN_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_IN | SST_DEFAULT_CELL_NBR), |
@@ -124,6 +129,7 @@ enum sst_swm_inputs { | |||
124 | * path IDs | 129 | * path IDs |
125 | */ | 130 | */ |
126 | enum sst_swm_outputs { | 131 | enum sst_swm_outputs { |
132 | SST_SWM_OUT_MODEM = (SST_PATH_INDEX_MODEM_OUT | SST_DEFAULT_CELL_NBR), | ||
127 | SST_SWM_OUT_CODEC0 = (SST_PATH_INDEX_CODEC_OUT0 | SST_DEFAULT_CELL_NBR), | 133 | SST_SWM_OUT_CODEC0 = (SST_PATH_INDEX_CODEC_OUT0 | SST_DEFAULT_CELL_NBR), |
128 | SST_SWM_OUT_CODEC1 = (SST_PATH_INDEX_CODEC_OUT1 | SST_DEFAULT_CELL_NBR), | 134 | SST_SWM_OUT_CODEC1 = (SST_PATH_INDEX_CODEC_OUT1 | SST_DEFAULT_CELL_NBR), |
129 | SST_SWM_OUT_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_OUT | SST_DEFAULT_CELL_NBR), | 135 | SST_SWM_OUT_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_OUT | SST_DEFAULT_CELL_NBR), |
diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index a4b458e77089..9b6e27385dc9 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c | |||
@@ -190,7 +190,8 @@ int sst_driver_ops(struct intel_sst_drv *sst) | |||
190 | 190 | ||
191 | default: | 191 | default: |
192 | dev_err(sst->dev, | 192 | dev_err(sst->dev, |
193 | "SST Driver capablities missing for dev_id: %x", sst->dev_id); | 193 | "SST Driver capabilities missing for dev_id: %x", |
194 | sst->dev_id); | ||
194 | return -EINVAL; | 195 | return -EINVAL; |
195 | }; | 196 | }; |
196 | } | 197 | } |
@@ -441,7 +442,7 @@ static int intel_sst_suspend(struct device *dev) | |||
441 | struct stream_info *stream = &ctx->streams[i]; | 442 | struct stream_info *stream = &ctx->streams[i]; |
442 | 443 | ||
443 | if (stream->status == STREAM_RUNNING) { | 444 | if (stream->status == STREAM_RUNNING) { |
444 | dev_err(dev, "stream %d is running, cant susupend, abort\n", i); | 445 | dev_err(dev, "stream %d is running, can't suspend, abort\n", i); |
445 | return -EBUSY; | 446 | return -EBUSY; |
446 | } | 447 | } |
447 | } | 448 | } |
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 4d3184971227..ba5c0d71720a 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c | |||
@@ -39,6 +39,8 @@ | |||
39 | #include <acpi/platform/aclinux.h> | 39 | #include <acpi/platform/aclinux.h> |
40 | #include <acpi/actypes.h> | 40 | #include <acpi/actypes.h> |
41 | #include <acpi/acpi_bus.h> | 41 | #include <acpi/acpi_bus.h> |
42 | #include <asm/cpu_device_id.h> | ||
43 | #include <asm/iosf_mbi.h> | ||
42 | #include "../sst-mfld-platform.h" | 44 | #include "../sst-mfld-platform.h" |
43 | #include "../../common/sst-dsp.h" | 45 | #include "../../common/sst-dsp.h" |
44 | #include "../../common/sst-acpi.h" | 46 | #include "../../common/sst-acpi.h" |
@@ -113,6 +115,28 @@ static const struct sst_res_info byt_rvp_res_info = { | |||
113 | .acpi_ipc_irq_index = 5, | 115 | .acpi_ipc_irq_index = 5, |
114 | }; | 116 | }; |
115 | 117 | ||
118 | /* BYTCR has different BIOS from BYT */ | ||
119 | static const struct sst_res_info bytcr_res_info = { | ||
120 | .shim_offset = 0x140000, | ||
121 | .shim_size = 0x000100, | ||
122 | .shim_phy_addr = SST_BYT_SHIM_PHY_ADDR, | ||
123 | .ssp0_offset = 0xa0000, | ||
124 | .ssp0_size = 0x1000, | ||
125 | .dma0_offset = 0x98000, | ||
126 | .dma0_size = 0x4000, | ||
127 | .dma1_offset = 0x9c000, | ||
128 | .dma1_size = 0x4000, | ||
129 | .iram_offset = 0x0c0000, | ||
130 | .iram_size = 0x14000, | ||
131 | .dram_offset = 0x100000, | ||
132 | .dram_size = 0x28000, | ||
133 | .mbox_offset = 0x144000, | ||
134 | .mbox_size = 0x1000, | ||
135 | .acpi_lpe_res_index = 0, | ||
136 | .acpi_ddr_index = 2, | ||
137 | .acpi_ipc_irq_index = 0 | ||
138 | }; | ||
139 | |||
116 | static struct sst_platform_info byt_rvp_platform_data = { | 140 | static struct sst_platform_info byt_rvp_platform_data = { |
117 | .probe_data = &byt_fwparse_info, | 141 | .probe_data = &byt_fwparse_info, |
118 | .ipc_info = &byt_ipc_info, | 142 | .ipc_info = &byt_ipc_info, |
@@ -142,7 +166,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) | |||
142 | rsrc = platform_get_resource(pdev, IORESOURCE_MEM, | 166 | rsrc = platform_get_resource(pdev, IORESOURCE_MEM, |
143 | ctx->pdata->res_info->acpi_lpe_res_index); | 167 | ctx->pdata->res_info->acpi_lpe_res_index); |
144 | if (!rsrc) { | 168 | if (!rsrc) { |
145 | dev_err(ctx->dev, "Invalid SHIM base from IFWI"); | 169 | dev_err(ctx->dev, "Invalid SHIM base from IFWI\n"); |
146 | return -EIO; | 170 | return -EIO; |
147 | } | 171 | } |
148 | dev_info(ctx->dev, "LPE base: %#x size:%#x", (unsigned int) rsrc->start, | 172 | dev_info(ctx->dev, "LPE base: %#x size:%#x", (unsigned int) rsrc->start, |
@@ -154,7 +178,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) | |||
154 | ctx->iram = devm_ioremap_nocache(ctx->dev, ctx->iram_base, | 178 | ctx->iram = devm_ioremap_nocache(ctx->dev, ctx->iram_base, |
155 | ctx->pdata->res_info->iram_size); | 179 | ctx->pdata->res_info->iram_size); |
156 | if (!ctx->iram) { | 180 | if (!ctx->iram) { |
157 | dev_err(ctx->dev, "unable to map IRAM"); | 181 | dev_err(ctx->dev, "unable to map IRAM\n"); |
158 | return -EIO; | 182 | return -EIO; |
159 | } | 183 | } |
160 | 184 | ||
@@ -164,7 +188,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) | |||
164 | ctx->dram = devm_ioremap_nocache(ctx->dev, ctx->dram_base, | 188 | ctx->dram = devm_ioremap_nocache(ctx->dev, ctx->dram_base, |
165 | ctx->pdata->res_info->dram_size); | 189 | ctx->pdata->res_info->dram_size); |
166 | if (!ctx->dram) { | 190 | if (!ctx->dram) { |
167 | dev_err(ctx->dev, "unable to map DRAM"); | 191 | dev_err(ctx->dev, "unable to map DRAM\n"); |
168 | return -EIO; | 192 | return -EIO; |
169 | } | 193 | } |
170 | 194 | ||
@@ -173,7 +197,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) | |||
173 | ctx->shim = devm_ioremap_nocache(ctx->dev, ctx->shim_phy_add, | 197 | ctx->shim = devm_ioremap_nocache(ctx->dev, ctx->shim_phy_add, |
174 | ctx->pdata->res_info->shim_size); | 198 | ctx->pdata->res_info->shim_size); |
175 | if (!ctx->shim) { | 199 | if (!ctx->shim) { |
176 | dev_err(ctx->dev, "unable to map SHIM"); | 200 | dev_err(ctx->dev, "unable to map SHIM\n"); |
177 | return -EIO; | 201 | return -EIO; |
178 | } | 202 | } |
179 | 203 | ||
@@ -186,7 +210,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) | |||
186 | ctx->mailbox = devm_ioremap_nocache(ctx->dev, ctx->mailbox_add, | 210 | ctx->mailbox = devm_ioremap_nocache(ctx->dev, ctx->mailbox_add, |
187 | ctx->pdata->res_info->mbox_size); | 211 | ctx->pdata->res_info->mbox_size); |
188 | if (!ctx->mailbox) { | 212 | if (!ctx->mailbox) { |
189 | dev_err(ctx->dev, "unable to map mailbox"); | 213 | dev_err(ctx->dev, "unable to map mailbox\n"); |
190 | return -EIO; | 214 | return -EIO; |
191 | } | 215 | } |
192 | 216 | ||
@@ -196,7 +220,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) | |||
196 | rsrc = platform_get_resource(pdev, IORESOURCE_MEM, | 220 | rsrc = platform_get_resource(pdev, IORESOURCE_MEM, |
197 | ctx->pdata->res_info->acpi_ddr_index); | 221 | ctx->pdata->res_info->acpi_ddr_index); |
198 | if (!rsrc) { | 222 | if (!rsrc) { |
199 | dev_err(ctx->dev, "Invalid DDR base from IFWI"); | 223 | dev_err(ctx->dev, "Invalid DDR base from IFWI\n"); |
200 | return -EIO; | 224 | return -EIO; |
201 | } | 225 | } |
202 | ctx->ddr_base = rsrc->start; | 226 | ctx->ddr_base = rsrc->start; |
@@ -205,7 +229,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) | |||
205 | ctx->ddr = devm_ioremap_nocache(ctx->dev, ctx->ddr_base, | 229 | ctx->ddr = devm_ioremap_nocache(ctx->dev, ctx->ddr_base, |
206 | resource_size(rsrc)); | 230 | resource_size(rsrc)); |
207 | if (!ctx->ddr) { | 231 | if (!ctx->ddr) { |
208 | dev_err(ctx->dev, "unable to map DDR"); | 232 | dev_err(ctx->dev, "unable to map DDR\n"); |
209 | return -EIO; | 233 | return -EIO; |
210 | } | 234 | } |
211 | 235 | ||
@@ -215,6 +239,46 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) | |||
215 | return 0; | 239 | return 0; |
216 | } | 240 | } |
217 | 241 | ||
242 | |||
243 | static int is_byt_cr(struct device *dev, bool *bytcr) | ||
244 | { | ||
245 | int status = 0; | ||
246 | |||
247 | if (IS_ENABLED(CONFIG_IOSF_MBI)) { | ||
248 | static const struct x86_cpu_id cpu_ids[] = { | ||
249 | { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */ | ||
250 | {} | ||
251 | }; | ||
252 | u32 bios_status; | ||
253 | |||
254 | if (!x86_match_cpu(cpu_ids) || !iosf_mbi_available()) { | ||
255 | /* bail silently */ | ||
256 | return status; | ||
257 | } | ||
258 | |||
259 | status = iosf_mbi_read(BT_MBI_UNIT_PMC, /* 0x04 PUNIT */ | ||
260 | MBI_REG_READ, /* 0x10 */ | ||
261 | 0x006, /* BIOS_CONFIG */ | ||
262 | &bios_status); | ||
263 | |||
264 | if (status) { | ||
265 | dev_err(dev, "could not read PUNIT BIOS_CONFIG\n"); | ||
266 | } else { | ||
267 | /* bits 26:27 mirror PMIC options */ | ||
268 | bios_status = (bios_status >> 26) & 3; | ||
269 | |||
270 | if ((bios_status == 1) || (bios_status == 3)) | ||
271 | *bytcr = true; | ||
272 | else | ||
273 | dev_info(dev, "BYT-CR not detected\n"); | ||
274 | } | ||
275 | } else { | ||
276 | dev_info(dev, "IOSF_MBI not enabled, no BYT-CR detection\n"); | ||
277 | } | ||
278 | return status; | ||
279 | } | ||
280 | |||
281 | |||
218 | static int sst_acpi_probe(struct platform_device *pdev) | 282 | static int sst_acpi_probe(struct platform_device *pdev) |
219 | { | 283 | { |
220 | struct device *dev = &pdev->dev; | 284 | struct device *dev = &pdev->dev; |
@@ -226,11 +290,12 @@ static int sst_acpi_probe(struct platform_device *pdev) | |||
226 | struct platform_device *plat_dev; | 290 | struct platform_device *plat_dev; |
227 | struct sst_platform_info *pdata; | 291 | struct sst_platform_info *pdata; |
228 | unsigned int dev_id; | 292 | unsigned int dev_id; |
293 | bool bytcr = false; | ||
229 | 294 | ||
230 | id = acpi_match_device(dev->driver->acpi_match_table, dev); | 295 | id = acpi_match_device(dev->driver->acpi_match_table, dev); |
231 | if (!id) | 296 | if (!id) |
232 | return -ENODEV; | 297 | return -ENODEV; |
233 | dev_dbg(dev, "for %s", id->id); | 298 | dev_dbg(dev, "for %s\n", id->id); |
234 | 299 | ||
235 | mach = (struct sst_acpi_mach *)id->driver_data; | 300 | mach = (struct sst_acpi_mach *)id->driver_data; |
236 | mach = sst_acpi_find_machine(mach); | 301 | mach = sst_acpi_find_machine(mach); |
@@ -251,6 +316,18 @@ static int sst_acpi_probe(struct platform_device *pdev) | |||
251 | 316 | ||
252 | dev_dbg(dev, "ACPI device id: %x\n", dev_id); | 317 | dev_dbg(dev, "ACPI device id: %x\n", dev_id); |
253 | 318 | ||
319 | ret = sst_alloc_drv_context(&ctx, dev, dev_id); | ||
320 | if (ret < 0) | ||
321 | return ret; | ||
322 | |||
323 | ret = is_byt_cr(dev, &bytcr); | ||
324 | if (!((ret < 0) || (bytcr == false))) { | ||
325 | dev_info(dev, "Detected Baytrail-CR platform\n"); | ||
326 | |||
327 | /* override resource info */ | ||
328 | byt_rvp_platform_data.res_info = &bytcr_res_info; | ||
329 | } | ||
330 | |||
254 | plat_dev = platform_device_register_data(dev, pdata->platform, -1, | 331 | plat_dev = platform_device_register_data(dev, pdata->platform, -1, |
255 | NULL, 0); | 332 | NULL, 0); |
256 | if (IS_ERR(plat_dev)) { | 333 | if (IS_ERR(plat_dev)) { |
@@ -271,10 +348,6 @@ static int sst_acpi_probe(struct platform_device *pdev) | |||
271 | return PTR_ERR(mdev); | 348 | return PTR_ERR(mdev); |
272 | } | 349 | } |
273 | 350 | ||
274 | ret = sst_alloc_drv_context(&ctx, dev, dev_id); | ||
275 | if (ret < 0) | ||
276 | return ret; | ||
277 | |||
278 | /* Fill sst platform data */ | 351 | /* Fill sst platform data */ |
279 | ctx->pdata = pdata; | 352 | ctx->pdata = pdata; |
280 | strcpy(ctx->firmware_name, mach->fw_filename); | 353 | strcpy(ctx->firmware_name, mach->fw_filename); |
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index dac03a06bfd8..5639f10774e6 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile | |||
@@ -1,6 +1,7 @@ | |||
1 | snd-soc-sst-haswell-objs := haswell.o | 1 | snd-soc-sst-haswell-objs := haswell.o |
2 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o | 2 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o |
3 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o | 3 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o |
4 | snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o | ||
4 | snd-soc-sst-broadwell-objs := broadwell.o | 5 | snd-soc-sst-broadwell-objs := broadwell.o |
5 | snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o | 6 | snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o |
6 | snd-soc-sst-bxt-rt298-objs := bxt_rt298.o | 7 | snd-soc-sst-bxt-rt298-objs := bxt_rt298.o |
@@ -19,6 +20,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o | |||
19 | obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o | 20 | obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o |
20 | obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o | 21 | obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o |
21 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o | 22 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o |
23 | obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o | ||
22 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o | 24 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o |
23 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o | 25 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o |
24 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o | 26 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o |
diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c new file mode 100644 index 000000000000..547e6705bf6d --- /dev/null +++ b/sound/soc/intel/boards/bdw-rt5677.c | |||
@@ -0,0 +1,347 @@ | |||
1 | /* | ||
2 | * ASoC machine driver for Intel Broadwell platforms with RT5677 codec | ||
3 | * | ||
4 | * Copyright (c) 2014, The Chromium OS Authors. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/gpio/consumer.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/jack.h> | ||
28 | |||
29 | #include "../common/sst-dsp.h" | ||
30 | #include "../haswell/sst-haswell-ipc.h" | ||
31 | |||
32 | #include "../../codecs/rt5677.h" | ||
33 | |||
34 | struct bdw_rt5677_priv { | ||
35 | struct gpio_desc *gpio_hp_en; | ||
36 | struct snd_soc_codec *codec; | ||
37 | }; | ||
38 | |||
39 | static int bdw_rt5677_event_hp(struct snd_soc_dapm_widget *w, | ||
40 | struct snd_kcontrol *k, int event) | ||
41 | { | ||
42 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
43 | struct snd_soc_card *card = dapm->card; | ||
44 | struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card); | ||
45 | |||
46 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
47 | msleep(70); | ||
48 | |||
49 | gpiod_set_value_cansleep(bdw_rt5677->gpio_hp_en, | ||
50 | SND_SOC_DAPM_EVENT_ON(event)); | ||
51 | |||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static const struct snd_soc_dapm_widget bdw_rt5677_widgets[] = { | ||
56 | SND_SOC_DAPM_HP("Headphone", bdw_rt5677_event_hp), | ||
57 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
58 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
59 | SND_SOC_DAPM_MIC("Local DMICs", NULL), | ||
60 | SND_SOC_DAPM_MIC("Remote DMICs", NULL), | ||
61 | }; | ||
62 | |||
63 | static const struct snd_soc_dapm_route bdw_rt5677_map[] = { | ||
64 | /* Speakers */ | ||
65 | {"Speaker", NULL, "PDM1L"}, | ||
66 | {"Speaker", NULL, "PDM1R"}, | ||
67 | |||
68 | /* Headset jack connectors */ | ||
69 | {"Headphone", NULL, "LOUT1"}, | ||
70 | {"Headphone", NULL, "LOUT2"}, | ||
71 | {"IN1P", NULL, "Headset Mic"}, | ||
72 | {"IN1N", NULL, "Headset Mic"}, | ||
73 | |||
74 | /* Digital MICs | ||
75 | * Local DMICs: the two DMICs on the mainboard | ||
76 | * Remote DMICs: the two DMICs on the camera module | ||
77 | */ | ||
78 | {"DMIC L1", NULL, "Remote DMICs"}, | ||
79 | {"DMIC R1", NULL, "Remote DMICs"}, | ||
80 | {"DMIC L2", NULL, "Local DMICs"}, | ||
81 | {"DMIC R2", NULL, "Local DMICs"}, | ||
82 | |||
83 | /* CODEC BE connections */ | ||
84 | {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, | ||
85 | {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, | ||
86 | }; | ||
87 | |||
88 | static const struct snd_kcontrol_new bdw_rt5677_controls[] = { | ||
89 | SOC_DAPM_PIN_SWITCH("Speaker"), | ||
90 | SOC_DAPM_PIN_SWITCH("Headphone"), | ||
91 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
92 | SOC_DAPM_PIN_SWITCH("Local DMICs"), | ||
93 | SOC_DAPM_PIN_SWITCH("Remote DMICs"), | ||
94 | }; | ||
95 | |||
96 | |||
97 | static struct snd_soc_jack headphone_jack; | ||
98 | static struct snd_soc_jack mic_jack; | ||
99 | |||
100 | static struct snd_soc_jack_pin headphone_jack_pin = { | ||
101 | .pin = "Headphone", | ||
102 | .mask = SND_JACK_HEADPHONE, | ||
103 | }; | ||
104 | |||
105 | static struct snd_soc_jack_pin mic_jack_pin = { | ||
106 | .pin = "Headset Mic", | ||
107 | .mask = SND_JACK_MICROPHONE, | ||
108 | }; | ||
109 | |||
110 | static struct snd_soc_jack_gpio headphone_jack_gpio = { | ||
111 | .name = "plug-det", | ||
112 | .report = SND_JACK_HEADPHONE, | ||
113 | .debounce_time = 200, | ||
114 | }; | ||
115 | |||
116 | static struct snd_soc_jack_gpio mic_jack_gpio = { | ||
117 | .name = "mic-present", | ||
118 | .report = SND_JACK_MICROPHONE, | ||
119 | .debounce_time = 200, | ||
120 | .invert = 1, | ||
121 | }; | ||
122 | |||
123 | static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, | ||
124 | struct snd_pcm_hw_params *params) | ||
125 | { | ||
126 | struct snd_interval *rate = hw_param_interval(params, | ||
127 | SNDRV_PCM_HW_PARAM_RATE); | ||
128 | struct snd_interval *channels = hw_param_interval(params, | ||
129 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
130 | |||
131 | /* The ADSP will covert the FE rate to 48k, stereo */ | ||
132 | rate->min = rate->max = 48000; | ||
133 | channels->min = channels->max = 2; | ||
134 | |||
135 | /* set SSP0 to 16 bit */ | ||
136 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | ||
137 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
138 | SNDRV_PCM_FORMAT_S16_LE); | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int bdw_rt5677_hw_params(struct snd_pcm_substream *substream, | ||
143 | struct snd_pcm_hw_params *params) | ||
144 | { | ||
145 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
146 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
147 | int ret; | ||
148 | |||
149 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_MCLK, 24576000, | ||
150 | SND_SOC_CLOCK_IN); | ||
151 | if (ret < 0) { | ||
152 | dev_err(rtd->dev, "can't set codec sysclk configuration\n"); | ||
153 | return ret; | ||
154 | } | ||
155 | |||
156 | return ret; | ||
157 | } | ||
158 | |||
159 | static struct snd_soc_ops bdw_rt5677_ops = { | ||
160 | .hw_params = bdw_rt5677_hw_params, | ||
161 | }; | ||
162 | |||
163 | static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd) | ||
164 | { | ||
165 | struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev); | ||
166 | struct sst_hsw *broadwell = pdata->dsp; | ||
167 | int ret; | ||
168 | |||
169 | /* Set ADSP SSP port settings */ | ||
170 | ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0, | ||
171 | SST_HSW_DEVICE_MCLK_FREQ_24_MHZ, | ||
172 | SST_HSW_DEVICE_CLOCK_MASTER, 9); | ||
173 | if (ret < 0) { | ||
174 | dev_err(rtd->dev, "error: failed to set device config\n"); | ||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) | ||
182 | { | ||
183 | struct bdw_rt5677_priv *bdw_rt5677 = | ||
184 | snd_soc_card_get_drvdata(rtd->card); | ||
185 | struct snd_soc_codec *codec = rtd->codec; | ||
186 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
187 | |||
188 | /* Enable codec ASRC function for Stereo DAC/Stereo1 ADC/DMIC/I2S1. | ||
189 | * The ASRC clock source is clk_i2s1_asrc. | ||
190 | */ | ||
191 | rt5677_sel_asrc_clk_src(codec, RT5677_DA_STEREO_FILTER | | ||
192 | RT5677_AD_STEREO1_FILTER | RT5677_I2S1_SOURCE, | ||
193 | RT5677_CLK_SEL_I2S1_ASRC); | ||
194 | |||
195 | /* Request rt5677 GPIO for headphone amp control */ | ||
196 | bdw_rt5677->gpio_hp_en = devm_gpiod_get_index(codec->dev, | ||
197 | "headphone-enable", 0, 0); | ||
198 | if (IS_ERR(bdw_rt5677->gpio_hp_en)) { | ||
199 | dev_err(codec->dev, "Can't find HP_AMP_SHDN_L gpio\n"); | ||
200 | return PTR_ERR(bdw_rt5677->gpio_hp_en); | ||
201 | } | ||
202 | gpiod_direction_output(bdw_rt5677->gpio_hp_en, 0); | ||
203 | |||
204 | /* Create and initialize headphone jack */ | ||
205 | if (!snd_soc_card_jack_new(rtd->card, "Headphone Jack", | ||
206 | SND_JACK_HEADPHONE, &headphone_jack, | ||
207 | &headphone_jack_pin, 1)) { | ||
208 | headphone_jack_gpio.gpiod_dev = codec->dev; | ||
209 | if (snd_soc_jack_add_gpios(&headphone_jack, 1, | ||
210 | &headphone_jack_gpio)) | ||
211 | dev_err(codec->dev, "Can't add headphone jack gpio\n"); | ||
212 | } else { | ||
213 | dev_err(codec->dev, "Can't create headphone jack\n"); | ||
214 | } | ||
215 | |||
216 | /* Create and initialize mic jack */ | ||
217 | if (!snd_soc_card_jack_new(rtd->card, "Mic Jack", | ||
218 | SND_JACK_MICROPHONE, &mic_jack, | ||
219 | &mic_jack_pin, 1)) { | ||
220 | mic_jack_gpio.gpiod_dev = codec->dev; | ||
221 | if (snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio)) | ||
222 | dev_err(codec->dev, "Can't add mic jack gpio\n"); | ||
223 | } else { | ||
224 | dev_err(codec->dev, "Can't create mic jack\n"); | ||
225 | } | ||
226 | bdw_rt5677->codec = codec; | ||
227 | |||
228 | snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | /* broadwell digital audio interface glue - connects codec <--> CPU */ | ||
233 | static struct snd_soc_dai_link bdw_rt5677_dais[] = { | ||
234 | /* Front End DAI links */ | ||
235 | { | ||
236 | .name = "System PCM", | ||
237 | .stream_name = "System Playback/Capture", | ||
238 | .cpu_dai_name = "System Pin", | ||
239 | .platform_name = "haswell-pcm-audio", | ||
240 | .dynamic = 1, | ||
241 | .codec_name = "snd-soc-dummy", | ||
242 | .codec_dai_name = "snd-soc-dummy-dai", | ||
243 | .init = bdw_rt5677_rtd_init, | ||
244 | .trigger = { | ||
245 | SND_SOC_DPCM_TRIGGER_POST, | ||
246 | SND_SOC_DPCM_TRIGGER_POST | ||
247 | }, | ||
248 | .dpcm_capture = 1, | ||
249 | .dpcm_playback = 1, | ||
250 | }, | ||
251 | |||
252 | /* Back End DAI links */ | ||
253 | { | ||
254 | /* SSP0 - Codec */ | ||
255 | .name = "Codec", | ||
256 | .id = 0, | ||
257 | .cpu_dai_name = "snd-soc-dummy-dai", | ||
258 | .platform_name = "snd-soc-dummy", | ||
259 | .no_pcm = 1, | ||
260 | .codec_name = "i2c-RT5677CE:00", | ||
261 | .codec_dai_name = "rt5677-aif1", | ||
262 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
263 | SND_SOC_DAIFMT_CBS_CFS, | ||
264 | .ignore_suspend = 1, | ||
265 | .ignore_pmdown_time = 1, | ||
266 | .be_hw_params_fixup = broadwell_ssp0_fixup, | ||
267 | .ops = &bdw_rt5677_ops, | ||
268 | .dpcm_playback = 1, | ||
269 | .dpcm_capture = 1, | ||
270 | .init = bdw_rt5677_init, | ||
271 | }, | ||
272 | }; | ||
273 | |||
274 | static int bdw_rt5677_suspend_pre(struct snd_soc_card *card) | ||
275 | { | ||
276 | struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card); | ||
277 | struct snd_soc_dapm_context *dapm; | ||
278 | |||
279 | if (bdw_rt5677->codec) { | ||
280 | dapm = snd_soc_codec_get_dapm(bdw_rt5677->codec); | ||
281 | snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); | ||
282 | } | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int bdw_rt5677_resume_post(struct snd_soc_card *card) | ||
287 | { | ||
288 | struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card); | ||
289 | struct snd_soc_dapm_context *dapm; | ||
290 | |||
291 | if (bdw_rt5677->codec) { | ||
292 | dapm = snd_soc_codec_get_dapm(bdw_rt5677->codec); | ||
293 | snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); | ||
294 | } | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | /* ASoC machine driver for Broadwell DSP + RT5677 */ | ||
299 | static struct snd_soc_card bdw_rt5677_card = { | ||
300 | .name = "bdw-rt5677", | ||
301 | .owner = THIS_MODULE, | ||
302 | .dai_link = bdw_rt5677_dais, | ||
303 | .num_links = ARRAY_SIZE(bdw_rt5677_dais), | ||
304 | .dapm_widgets = bdw_rt5677_widgets, | ||
305 | .num_dapm_widgets = ARRAY_SIZE(bdw_rt5677_widgets), | ||
306 | .dapm_routes = bdw_rt5677_map, | ||
307 | .num_dapm_routes = ARRAY_SIZE(bdw_rt5677_map), | ||
308 | .controls = bdw_rt5677_controls, | ||
309 | .num_controls = ARRAY_SIZE(bdw_rt5677_controls), | ||
310 | .fully_routed = true, | ||
311 | .suspend_pre = bdw_rt5677_suspend_pre, | ||
312 | .resume_post = bdw_rt5677_resume_post, | ||
313 | }; | ||
314 | |||
315 | static int bdw_rt5677_probe(struct platform_device *pdev) | ||
316 | { | ||
317 | struct bdw_rt5677_priv *bdw_rt5677; | ||
318 | |||
319 | bdw_rt5677_card.dev = &pdev->dev; | ||
320 | |||
321 | /* Allocate driver private struct */ | ||
322 | bdw_rt5677 = devm_kzalloc(&pdev->dev, sizeof(struct bdw_rt5677_priv), | ||
323 | GFP_KERNEL); | ||
324 | if (!bdw_rt5677) { | ||
325 | dev_err(&pdev->dev, "Can't allocate bdw_rt5677\n"); | ||
326 | return -ENOMEM; | ||
327 | } | ||
328 | |||
329 | snd_soc_card_set_drvdata(&bdw_rt5677_card, bdw_rt5677); | ||
330 | |||
331 | return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5677_card); | ||
332 | } | ||
333 | |||
334 | static struct platform_driver bdw_rt5677_audio = { | ||
335 | .probe = bdw_rt5677_probe, | ||
336 | .driver = { | ||
337 | .name = "bdw-rt5677", | ||
338 | }, | ||
339 | }; | ||
340 | |||
341 | module_platform_driver(bdw_rt5677_audio) | ||
342 | |||
343 | /* Module information */ | ||
344 | MODULE_AUTHOR("Ben Zhang"); | ||
345 | MODULE_DESCRIPTION("Intel Broadwell RT5677 machine driver"); | ||
346 | MODULE_LICENSE("GPL v2"); | ||
347 | MODULE_ALIAS("platform:bdw-rt5677"); | ||
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 3774b117d365..6532b8f0ab2f 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c | |||
@@ -37,6 +37,7 @@ enum { | |||
37 | BXT_DPCM_AUDIO_PB = 0, | 37 | BXT_DPCM_AUDIO_PB = 0, |
38 | BXT_DPCM_AUDIO_CP, | 38 | BXT_DPCM_AUDIO_CP, |
39 | BXT_DPCM_AUDIO_REF_CP, | 39 | BXT_DPCM_AUDIO_REF_CP, |
40 | BXT_DPCM_AUDIO_DMIC_CP, | ||
40 | BXT_DPCM_AUDIO_HDMI1_PB, | 41 | BXT_DPCM_AUDIO_HDMI1_PB, |
41 | BXT_DPCM_AUDIO_HDMI2_PB, | 42 | BXT_DPCM_AUDIO_HDMI2_PB, |
42 | BXT_DPCM_AUDIO_HDMI3_PB, | 43 | BXT_DPCM_AUDIO_HDMI3_PB, |
@@ -252,10 +253,56 @@ static struct snd_soc_ops broxton_da7219_ops = { | |||
252 | .hw_free = broxton_da7219_hw_free, | 253 | .hw_free = broxton_da7219_hw_free, |
253 | }; | 254 | }; |
254 | 255 | ||
256 | static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, | ||
257 | struct snd_pcm_hw_params *params) | ||
258 | { | ||
259 | struct snd_interval *channels = hw_param_interval(params, | ||
260 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
261 | channels->min = channels->max = DUAL_CHANNEL; | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static int broxton_dmic_startup(struct snd_pcm_substream *substream) | ||
267 | { | ||
268 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
269 | |||
270 | runtime->hw.channels_max = DUAL_CHANNEL; | ||
271 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
272 | &constraints_channels); | ||
273 | |||
274 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
275 | SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); | ||
276 | } | ||
277 | |||
278 | static const struct snd_soc_ops broxton_dmic_ops = { | ||
279 | .startup = broxton_dmic_startup, | ||
280 | }; | ||
281 | |||
282 | static const unsigned int rates_16000[] = { | ||
283 | 16000, | ||
284 | }; | ||
285 | |||
286 | static const struct snd_pcm_hw_constraint_list constraints_16000 = { | ||
287 | .count = ARRAY_SIZE(rates_16000), | ||
288 | .list = rates_16000, | ||
289 | }; | ||
290 | |||
291 | static int broxton_refcap_startup(struct snd_pcm_substream *substream) | ||
292 | { | ||
293 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
294 | SNDRV_PCM_HW_PARAM_RATE, | ||
295 | &constraints_16000); | ||
296 | }; | ||
297 | |||
298 | static struct snd_soc_ops broxton_refcap_ops = { | ||
299 | .startup = broxton_refcap_startup, | ||
300 | }; | ||
301 | |||
255 | /* broxton digital audio interface glue - connects codec <--> CPU */ | 302 | /* broxton digital audio interface glue - connects codec <--> CPU */ |
256 | static struct snd_soc_dai_link broxton_dais[] = { | 303 | static struct snd_soc_dai_link broxton_dais[] = { |
257 | /* Front End DAI links */ | 304 | /* Front End DAI links */ |
258 | [BXT_DPCM_AUDIO_PB] | 305 | [BXT_DPCM_AUDIO_PB] = |
259 | { | 306 | { |
260 | .name = "Bxt Audio Port", | 307 | .name = "Bxt Audio Port", |
261 | .stream_name = "Audio", | 308 | .stream_name = "Audio", |
@@ -271,7 +318,7 @@ static struct snd_soc_dai_link broxton_dais[] = { | |||
271 | .dpcm_playback = 1, | 318 | .dpcm_playback = 1, |
272 | .ops = &broxton_da7219_fe_ops, | 319 | .ops = &broxton_da7219_fe_ops, |
273 | }, | 320 | }, |
274 | [BXT_DPCM_AUDIO_CP] | 321 | [BXT_DPCM_AUDIO_CP] = |
275 | { | 322 | { |
276 | .name = "Bxt Audio Capture Port", | 323 | .name = "Bxt Audio Capture Port", |
277 | .stream_name = "Audio Record", | 324 | .stream_name = "Audio Record", |
@@ -286,7 +333,7 @@ static struct snd_soc_dai_link broxton_dais[] = { | |||
286 | .dpcm_capture = 1, | 333 | .dpcm_capture = 1, |
287 | .ops = &broxton_da7219_fe_ops, | 334 | .ops = &broxton_da7219_fe_ops, |
288 | }, | 335 | }, |
289 | [BXT_DPCM_AUDIO_REF_CP] | 336 | [BXT_DPCM_AUDIO_REF_CP] = |
290 | { | 337 | { |
291 | .name = "Bxt Audio Reference cap", | 338 | .name = "Bxt Audio Reference cap", |
292 | .stream_name = "Refcap", | 339 | .stream_name = "Refcap", |
@@ -299,8 +346,23 @@ static struct snd_soc_dai_link broxton_dais[] = { | |||
299 | .ignore_suspend = 1, | 346 | .ignore_suspend = 1, |
300 | .nonatomic = 1, | 347 | .nonatomic = 1, |
301 | .dynamic = 1, | 348 | .dynamic = 1, |
349 | .ops = &broxton_refcap_ops, | ||
350 | }, | ||
351 | [BXT_DPCM_AUDIO_DMIC_CP] | ||
352 | { | ||
353 | .name = "Bxt Audio DMIC cap", | ||
354 | .stream_name = "dmiccap", | ||
355 | .cpu_dai_name = "DMIC Pin", | ||
356 | .codec_name = "snd-soc-dummy", | ||
357 | .codec_dai_name = "snd-soc-dummy-dai", | ||
358 | .platform_name = "0000:00:0e.0", | ||
359 | .init = NULL, | ||
360 | .dpcm_capture = 1, | ||
361 | .nonatomic = 1, | ||
362 | .dynamic = 1, | ||
363 | .ops = &broxton_dmic_ops, | ||
302 | }, | 364 | }, |
303 | [BXT_DPCM_AUDIO_HDMI1_PB] | 365 | [BXT_DPCM_AUDIO_HDMI1_PB] = |
304 | { | 366 | { |
305 | .name = "Bxt HDMI Port1", | 367 | .name = "Bxt HDMI Port1", |
306 | .stream_name = "Hdmi1", | 368 | .stream_name = "Hdmi1", |
@@ -313,7 +375,7 @@ static struct snd_soc_dai_link broxton_dais[] = { | |||
313 | .nonatomic = 1, | 375 | .nonatomic = 1, |
314 | .dynamic = 1, | 376 | .dynamic = 1, |
315 | }, | 377 | }, |
316 | [BXT_DPCM_AUDIO_HDMI2_PB] | 378 | [BXT_DPCM_AUDIO_HDMI2_PB] = |
317 | { | 379 | { |
318 | .name = "Bxt HDMI Port2", | 380 | .name = "Bxt HDMI Port2", |
319 | .stream_name = "Hdmi2", | 381 | .stream_name = "Hdmi2", |
@@ -326,7 +388,7 @@ static struct snd_soc_dai_link broxton_dais[] = { | |||
326 | .nonatomic = 1, | 388 | .nonatomic = 1, |
327 | .dynamic = 1, | 389 | .dynamic = 1, |
328 | }, | 390 | }, |
329 | [BXT_DPCM_AUDIO_HDMI3_PB] | 391 | [BXT_DPCM_AUDIO_HDMI3_PB] = |
330 | { | 392 | { |
331 | .name = "Bxt HDMI Port3", | 393 | .name = "Bxt HDMI Port3", |
332 | .stream_name = "Hdmi3", | 394 | .stream_name = "Hdmi3", |
@@ -382,6 +444,7 @@ static struct snd_soc_dai_link broxton_dais[] = { | |||
382 | .codec_dai_name = "dmic-hifi", | 444 | .codec_dai_name = "dmic-hifi", |
383 | .platform_name = "0000:00:0e.0", | 445 | .platform_name = "0000:00:0e.0", |
384 | .ignore_suspend = 1, | 446 | .ignore_suspend = 1, |
447 | .be_hw_params_fixup = broxton_dmic_fixup, | ||
385 | .dpcm_capture = 1, | 448 | .dpcm_capture = 1, |
386 | .no_pcm = 1, | 449 | .no_pcm = 1, |
387 | }, | 450 | }, |
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 253d7bfbf511..d610bdca1608 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c | |||
@@ -271,7 +271,7 @@ static const struct snd_soc_ops broxton_rt286_fe_ops = { | |||
271 | /* broxton digital audio interface glue - connects codec <--> CPU */ | 271 | /* broxton digital audio interface glue - connects codec <--> CPU */ |
272 | static struct snd_soc_dai_link broxton_rt298_dais[] = { | 272 | static struct snd_soc_dai_link broxton_rt298_dais[] = { |
273 | /* Front End DAI links */ | 273 | /* Front End DAI links */ |
274 | [BXT_DPCM_AUDIO_PB] | 274 | [BXT_DPCM_AUDIO_PB] = |
275 | { | 275 | { |
276 | .name = "Bxt Audio Port", | 276 | .name = "Bxt Audio Port", |
277 | .stream_name = "Audio", | 277 | .stream_name = "Audio", |
@@ -286,7 +286,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { | |||
286 | .dpcm_playback = 1, | 286 | .dpcm_playback = 1, |
287 | .ops = &broxton_rt286_fe_ops, | 287 | .ops = &broxton_rt286_fe_ops, |
288 | }, | 288 | }, |
289 | [BXT_DPCM_AUDIO_CP] | 289 | [BXT_DPCM_AUDIO_CP] = |
290 | { | 290 | { |
291 | .name = "Bxt Audio Capture Port", | 291 | .name = "Bxt Audio Capture Port", |
292 | .stream_name = "Audio Record", | 292 | .stream_name = "Audio Record", |
@@ -300,7 +300,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { | |||
300 | .dpcm_capture = 1, | 300 | .dpcm_capture = 1, |
301 | .ops = &broxton_rt286_fe_ops, | 301 | .ops = &broxton_rt286_fe_ops, |
302 | }, | 302 | }, |
303 | [BXT_DPCM_AUDIO_REF_CP] | 303 | [BXT_DPCM_AUDIO_REF_CP] = |
304 | { | 304 | { |
305 | .name = "Bxt Audio Reference cap", | 305 | .name = "Bxt Audio Reference cap", |
306 | .stream_name = "refcap", | 306 | .stream_name = "refcap", |
@@ -313,7 +313,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { | |||
313 | .nonatomic = 1, | 313 | .nonatomic = 1, |
314 | .dynamic = 1, | 314 | .dynamic = 1, |
315 | }, | 315 | }, |
316 | [BXT_DPCM_AUDIO_DMIC_CP] | 316 | [BXT_DPCM_AUDIO_DMIC_CP] = |
317 | { | 317 | { |
318 | .name = "Bxt Audio DMIC cap", | 318 | .name = "Bxt Audio DMIC cap", |
319 | .stream_name = "dmiccap", | 319 | .stream_name = "dmiccap", |
@@ -327,7 +327,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { | |||
327 | .dynamic = 1, | 327 | .dynamic = 1, |
328 | .ops = &broxton_dmic_ops, | 328 | .ops = &broxton_dmic_ops, |
329 | }, | 329 | }, |
330 | [BXT_DPCM_AUDIO_HDMI1_PB] | 330 | [BXT_DPCM_AUDIO_HDMI1_PB] = |
331 | { | 331 | { |
332 | .name = "Bxt HDMI Port1", | 332 | .name = "Bxt HDMI Port1", |
333 | .stream_name = "Hdmi1", | 333 | .stream_name = "Hdmi1", |
@@ -340,7 +340,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { | |||
340 | .nonatomic = 1, | 340 | .nonatomic = 1, |
341 | .dynamic = 1, | 341 | .dynamic = 1, |
342 | }, | 342 | }, |
343 | [BXT_DPCM_AUDIO_HDMI2_PB] | 343 | [BXT_DPCM_AUDIO_HDMI2_PB] = |
344 | { | 344 | { |
345 | .name = "Bxt HDMI Port2", | 345 | .name = "Bxt HDMI Port2", |
346 | .stream_name = "Hdmi2", | 346 | .stream_name = "Hdmi2", |
@@ -353,7 +353,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { | |||
353 | .nonatomic = 1, | 353 | .nonatomic = 1, |
354 | .dynamic = 1, | 354 | .dynamic = 1, |
355 | }, | 355 | }, |
356 | [BXT_DPCM_AUDIO_HDMI3_PB] | 356 | [BXT_DPCM_AUDIO_HDMI3_PB] = |
357 | { | 357 | { |
358 | .name = "Bxt HDMI Port3", | 358 | .name = "Bxt HDMI Port3", |
359 | .stream_name = "Hdmi3", | 359 | .stream_name = "Hdmi3", |
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 88efb62439ba..bff77a1f27fc 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c | |||
@@ -24,6 +24,9 @@ | |||
24 | #include <linux/device.h> | 24 | #include <linux/device.h> |
25 | #include <linux/dmi.h> | 25 | #include <linux/dmi.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <asm/cpu_device_id.h> | ||
28 | #include <asm/platform_sst_audio.h> | ||
29 | #include <linux/clk.h> | ||
27 | #include <sound/pcm.h> | 30 | #include <sound/pcm.h> |
28 | #include <sound/pcm_params.h> | 31 | #include <sound/pcm_params.h> |
29 | #include <sound/soc.h> | 32 | #include <sound/soc.h> |
@@ -31,42 +34,153 @@ | |||
31 | #include "../../codecs/rt5640.h" | 34 | #include "../../codecs/rt5640.h" |
32 | #include "../atom/sst-atom-controls.h" | 35 | #include "../atom/sst-atom-controls.h" |
33 | #include "../common/sst-acpi.h" | 36 | #include "../common/sst-acpi.h" |
37 | #include "../common/sst-dsp.h" | ||
34 | 38 | ||
35 | enum { | 39 | enum { |
36 | BYT_RT5640_DMIC1_MAP, | 40 | BYT_RT5640_DMIC1_MAP, |
37 | BYT_RT5640_DMIC2_MAP, | 41 | BYT_RT5640_DMIC2_MAP, |
38 | BYT_RT5640_IN1_MAP, | 42 | BYT_RT5640_IN1_MAP, |
43 | BYT_RT5640_IN3_MAP, | ||
39 | }; | 44 | }; |
40 | 45 | ||
41 | #define BYT_RT5640_MAP(quirk) ((quirk) & 0xff) | 46 | #define BYT_RT5640_MAP(quirk) ((quirk) & 0xff) |
42 | #define BYT_RT5640_DMIC_EN BIT(16) | 47 | #define BYT_RT5640_DMIC_EN BIT(16) |
48 | #define BYT_RT5640_MONO_SPEAKER BIT(17) | ||
49 | #define BYT_RT5640_DIFF_MIC BIT(18) /* defaut is single-ended */ | ||
50 | #define BYT_RT5640_SSP2_AIF2 BIT(19) /* default is using AIF1 */ | ||
51 | #define BYT_RT5640_SSP0_AIF1 BIT(20) | ||
52 | #define BYT_RT5640_SSP0_AIF2 BIT(21) | ||
53 | #define BYT_RT5640_MCLK_EN BIT(22) | ||
54 | #define BYT_RT5640_MCLK_25MHZ BIT(23) | ||
55 | |||
56 | struct byt_rt5640_private { | ||
57 | struct clk *mclk; | ||
58 | }; | ||
43 | 59 | ||
44 | static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | | 60 | static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | |
45 | BYT_RT5640_DMIC_EN; | 61 | BYT_RT5640_DMIC_EN | |
62 | BYT_RT5640_MCLK_EN; | ||
63 | |||
64 | static void log_quirks(struct device *dev) | ||
65 | { | ||
66 | if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_DMIC1_MAP) | ||
67 | dev_info(dev, "quirk DMIC1_MAP enabled"); | ||
68 | if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_DMIC2_MAP) | ||
69 | dev_info(dev, "quirk DMIC2_MAP enabled"); | ||
70 | if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_IN1_MAP) | ||
71 | dev_info(dev, "quirk IN1_MAP enabled"); | ||
72 | if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_IN3_MAP) | ||
73 | dev_info(dev, "quirk IN3_MAP enabled"); | ||
74 | if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) | ||
75 | dev_info(dev, "quirk DMIC enabled"); | ||
76 | if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) | ||
77 | dev_info(dev, "quirk MONO_SPEAKER enabled"); | ||
78 | if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) | ||
79 | dev_info(dev, "quirk DIFF_MIC enabled"); | ||
80 | if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) | ||
81 | dev_info(dev, "quirk SSP2_AIF2 enabled"); | ||
82 | if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) | ||
83 | dev_info(dev, "quirk SSP0_AIF1 enabled"); | ||
84 | if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2) | ||
85 | dev_info(dev, "quirk SSP0_AIF2 enabled"); | ||
86 | if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN) | ||
87 | dev_info(dev, "quirk MCLK_EN enabled"); | ||
88 | if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) | ||
89 | dev_info(dev, "quirk MCLK_25MHZ enabled"); | ||
90 | } | ||
91 | |||
92 | |||
93 | #define BYT_CODEC_DAI1 "rt5640-aif1" | ||
94 | #define BYT_CODEC_DAI2 "rt5640-aif2" | ||
95 | |||
96 | static inline struct snd_soc_dai *byt_get_codec_dai(struct snd_soc_card *card) | ||
97 | { | ||
98 | struct snd_soc_pcm_runtime *rtd; | ||
99 | |||
100 | list_for_each_entry(rtd, &card->rtd_list, list) { | ||
101 | if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI1, | ||
102 | strlen(BYT_CODEC_DAI1))) | ||
103 | return rtd->codec_dai; | ||
104 | if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI2, | ||
105 | strlen(BYT_CODEC_DAI2))) | ||
106 | return rtd->codec_dai; | ||
107 | |||
108 | } | ||
109 | return NULL; | ||
110 | } | ||
111 | |||
112 | static int platform_clock_control(struct snd_soc_dapm_widget *w, | ||
113 | struct snd_kcontrol *k, int event) | ||
114 | { | ||
115 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
116 | struct snd_soc_card *card = dapm->card; | ||
117 | struct snd_soc_dai *codec_dai; | ||
118 | struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); | ||
119 | int ret; | ||
120 | |||
121 | codec_dai = byt_get_codec_dai(card); | ||
122 | if (!codec_dai) { | ||
123 | dev_err(card->dev, | ||
124 | "Codec dai not found; Unable to set platform clock\n"); | ||
125 | return -EIO; | ||
126 | } | ||
127 | |||
128 | if (SND_SOC_DAPM_EVENT_ON(event)) { | ||
129 | if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) { | ||
130 | ret = clk_prepare_enable(priv->mclk); | ||
131 | if (ret < 0) { | ||
132 | dev_err(card->dev, | ||
133 | "could not configure MCLK state"); | ||
134 | return ret; | ||
135 | } | ||
136 | } | ||
137 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, | ||
138 | 48000 * 512, | ||
139 | SND_SOC_CLOCK_IN); | ||
140 | } else { | ||
141 | /* | ||
142 | * Set codec clock source to internal clock before | ||
143 | * turning off the platform clock. Codec needs clock | ||
144 | * for Jack detection and button press | ||
145 | */ | ||
146 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_RCCLK, | ||
147 | 0, | ||
148 | SND_SOC_CLOCK_IN); | ||
149 | if (!ret) { | ||
150 | if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) | ||
151 | clk_disable_unprepare(priv->mclk); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | if (ret < 0) { | ||
156 | dev_err(card->dev, "can't set codec sysclk: %d\n", ret); | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | return 0; | ||
161 | } | ||
46 | 162 | ||
47 | static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { | 163 | static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { |
48 | SND_SOC_DAPM_HP("Headphone", NULL), | 164 | SND_SOC_DAPM_HP("Headphone", NULL), |
49 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | 165 | SND_SOC_DAPM_MIC("Headset Mic", NULL), |
50 | SND_SOC_DAPM_MIC("Internal Mic", NULL), | 166 | SND_SOC_DAPM_MIC("Internal Mic", NULL), |
51 | SND_SOC_DAPM_SPK("Speaker", NULL), | 167 | SND_SOC_DAPM_SPK("Speaker", NULL), |
168 | SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, | ||
169 | platform_clock_control, SND_SOC_DAPM_PRE_PMU | | ||
170 | SND_SOC_DAPM_POST_PMD), | ||
171 | |||
52 | }; | 172 | }; |
53 | 173 | ||
54 | static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { | 174 | static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { |
55 | {"AIF1 Playback", NULL, "ssp2 Tx"}, | 175 | {"Headphone", NULL, "Platform Clock"}, |
56 | {"ssp2 Tx", NULL, "codec_out0"}, | 176 | {"Headset Mic", NULL, "Platform Clock"}, |
57 | {"ssp2 Tx", NULL, "codec_out1"}, | 177 | {"Internal Mic", NULL, "Platform Clock"}, |
58 | {"codec_in0", NULL, "ssp2 Rx"}, | 178 | {"Speaker", NULL, "Platform Clock"}, |
59 | {"codec_in1", NULL, "ssp2 Rx"}, | ||
60 | {"ssp2 Rx", NULL, "AIF1 Capture"}, | ||
61 | 179 | ||
62 | {"Headset Mic", NULL, "MICBIAS1"}, | 180 | {"Headset Mic", NULL, "MICBIAS1"}, |
63 | {"IN2P", NULL, "Headset Mic"}, | 181 | {"IN2P", NULL, "Headset Mic"}, |
64 | {"Headphone", NULL, "HPOL"}, | 182 | {"Headphone", NULL, "HPOL"}, |
65 | {"Headphone", NULL, "HPOR"}, | 183 | {"Headphone", NULL, "HPOR"}, |
66 | {"Speaker", NULL, "SPOLP"}, | ||
67 | {"Speaker", NULL, "SPOLN"}, | ||
68 | {"Speaker", NULL, "SPORP"}, | ||
69 | {"Speaker", NULL, "SPORN"}, | ||
70 | }; | 184 | }; |
71 | 185 | ||
72 | static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = { | 186 | static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = { |
@@ -82,6 +196,59 @@ static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { | |||
82 | {"IN1P", NULL, "Internal Mic"}, | 196 | {"IN1P", NULL, "Internal Mic"}, |
83 | }; | 197 | }; |
84 | 198 | ||
199 | static const struct snd_soc_dapm_route byt_rt5640_intmic_in3_map[] = { | ||
200 | {"Internal Mic", NULL, "MICBIAS1"}, | ||
201 | {"IN3P", NULL, "Internal Mic"}, | ||
202 | }; | ||
203 | |||
204 | static const struct snd_soc_dapm_route byt_rt5640_ssp2_aif1_map[] = { | ||
205 | {"ssp2 Tx", NULL, "codec_out0"}, | ||
206 | {"ssp2 Tx", NULL, "codec_out1"}, | ||
207 | {"codec_in0", NULL, "ssp2 Rx"}, | ||
208 | {"codec_in1", NULL, "ssp2 Rx"}, | ||
209 | |||
210 | {"AIF1 Playback", NULL, "ssp2 Tx"}, | ||
211 | {"ssp2 Rx", NULL, "AIF1 Capture"}, | ||
212 | }; | ||
213 | |||
214 | static const struct snd_soc_dapm_route byt_rt5640_ssp2_aif2_map[] = { | ||
215 | {"ssp2 Tx", NULL, "codec_out0"}, | ||
216 | {"ssp2 Tx", NULL, "codec_out1"}, | ||
217 | {"codec_in0", NULL, "ssp2 Rx"}, | ||
218 | {"codec_in1", NULL, "ssp2 Rx"}, | ||
219 | |||
220 | {"AIF2 Playback", NULL, "ssp2 Tx"}, | ||
221 | {"ssp2 Rx", NULL, "AIF2 Capture"}, | ||
222 | }; | ||
223 | |||
224 | static const struct snd_soc_dapm_route byt_rt5640_ssp0_aif1_map[] = { | ||
225 | {"ssp0 Tx", NULL, "modem_out"}, | ||
226 | {"modem_in", NULL, "ssp0 Rx"}, | ||
227 | |||
228 | {"AIF1 Playback", NULL, "ssp0 Tx"}, | ||
229 | {"ssp0 Rx", NULL, "AIF1 Capture"}, | ||
230 | }; | ||
231 | |||
232 | static const struct snd_soc_dapm_route byt_rt5640_ssp0_aif2_map[] = { | ||
233 | {"ssp0 Tx", NULL, "modem_out"}, | ||
234 | {"modem_in", NULL, "ssp0 Rx"}, | ||
235 | |||
236 | {"AIF2 Playback", NULL, "ssp0 Tx"}, | ||
237 | {"ssp0 Rx", NULL, "AIF2 Capture"}, | ||
238 | }; | ||
239 | |||
240 | static const struct snd_soc_dapm_route byt_rt5640_stereo_spk_map[] = { | ||
241 | {"Speaker", NULL, "SPOLP"}, | ||
242 | {"Speaker", NULL, "SPOLN"}, | ||
243 | {"Speaker", NULL, "SPORP"}, | ||
244 | {"Speaker", NULL, "SPORN"}, | ||
245 | }; | ||
246 | |||
247 | static const struct snd_soc_dapm_route byt_rt5640_mono_spk_map[] = { | ||
248 | {"Speaker", NULL, "SPOLP"}, | ||
249 | {"Speaker", NULL, "SPOLN"}, | ||
250 | }; | ||
251 | |||
85 | static const struct snd_kcontrol_new byt_rt5640_controls[] = { | 252 | static const struct snd_kcontrol_new byt_rt5640_controls[] = { |
86 | SOC_DAPM_PIN_SWITCH("Headphone"), | 253 | SOC_DAPM_PIN_SWITCH("Headphone"), |
87 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | 254 | SOC_DAPM_PIN_SWITCH("Headset Mic"), |
@@ -96,19 +263,46 @@ static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream, | |||
96 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 263 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
97 | int ret; | 264 | int ret; |
98 | 265 | ||
99 | snd_soc_dai_set_bclk_ratio(codec_dai, 50); | ||
100 | |||
101 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, | 266 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, |
102 | params_rate(params) * 512, | 267 | params_rate(params) * 512, |
103 | SND_SOC_CLOCK_IN); | 268 | SND_SOC_CLOCK_IN); |
269 | |||
104 | if (ret < 0) { | 270 | if (ret < 0) { |
105 | dev_err(rtd->dev, "can't set codec clock %d\n", ret); | 271 | dev_err(rtd->dev, "can't set codec clock %d\n", ret); |
106 | return ret; | 272 | return ret; |
107 | } | 273 | } |
108 | 274 | ||
109 | ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1, | 275 | if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) { |
110 | params_rate(params) * 50, | 276 | /* use bitclock as PLL input */ |
111 | params_rate(params) * 512); | 277 | if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || |
278 | (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { | ||
279 | |||
280 | /* 2x16 bit slots on SSP0 */ | ||
281 | ret = snd_soc_dai_set_pll(codec_dai, 0, | ||
282 | RT5640_PLL1_S_BCLK1, | ||
283 | params_rate(params) * 32, | ||
284 | params_rate(params) * 512); | ||
285 | } else { | ||
286 | /* 2x15 bit slots on SSP2 */ | ||
287 | ret = snd_soc_dai_set_pll(codec_dai, 0, | ||
288 | RT5640_PLL1_S_BCLK1, | ||
289 | params_rate(params) * 50, | ||
290 | params_rate(params) * 512); | ||
291 | } | ||
292 | } else { | ||
293 | if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) { | ||
294 | ret = snd_soc_dai_set_pll(codec_dai, 0, | ||
295 | RT5640_PLL1_S_MCLK, | ||
296 | 25000000, | ||
297 | params_rate(params) * 512); | ||
298 | } else { | ||
299 | ret = snd_soc_dai_set_pll(codec_dai, 0, | ||
300 | RT5640_PLL1_S_MCLK, | ||
301 | 19200000, | ||
302 | params_rate(params) * 512); | ||
303 | } | ||
304 | } | ||
305 | |||
112 | if (ret < 0) { | 306 | if (ret < 0) { |
113 | dev_err(rtd->dev, "can't set codec pll: %d\n", ret); | 307 | dev_err(rtd->dev, "can't set codec pll: %d\n", ret); |
114 | return ret; | 308 | return ret; |
@@ -127,27 +321,73 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { | |||
127 | { | 321 | { |
128 | .callback = byt_rt5640_quirk_cb, | 322 | .callback = byt_rt5640_quirk_cb, |
129 | .matches = { | 323 | .matches = { |
130 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), | 324 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
131 | DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"), | 325 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), |
326 | }, | ||
327 | .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP | | ||
328 | BYT_RT5640_MCLK_EN), | ||
329 | }, | ||
330 | { | ||
331 | .callback = byt_rt5640_quirk_cb, | ||
332 | .matches = { | ||
333 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), | ||
334 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"), | ||
132 | }, | 335 | }, |
133 | .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, | 336 | .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP | |
337 | BYT_RT5640_MONO_SPEAKER | | ||
338 | BYT_RT5640_DIFF_MIC | | ||
339 | BYT_RT5640_SSP0_AIF2 | | ||
340 | BYT_RT5640_MCLK_EN | ||
341 | ), | ||
134 | }, | 342 | }, |
135 | { | 343 | { |
136 | .callback = byt_rt5640_quirk_cb, | 344 | .callback = byt_rt5640_quirk_cb, |
137 | .matches = { | 345 | .matches = { |
138 | DMI_MATCH(DMI_SYS_VENDOR, "DellInc."), | 346 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "DellInc."), |
139 | DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), | 347 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), |
140 | }, | 348 | }, |
141 | .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP | | 349 | .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP | |
350 | BYT_RT5640_DMIC_EN | | ||
351 | BYT_RT5640_MCLK_EN), | ||
352 | }, | ||
353 | { | ||
354 | .callback = byt_rt5640_quirk_cb, | ||
355 | .matches = { | ||
356 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | ||
357 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"), | ||
358 | }, | ||
359 | .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP | | ||
360 | BYT_RT5640_MCLK_EN), | ||
361 | }, | ||
362 | { | ||
363 | .callback = byt_rt5640_quirk_cb, | ||
364 | .matches = { | ||
365 | DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), | ||
366 | DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), | ||
367 | }, | ||
368 | .driver_data = (unsigned long *)(BYT_RT5640_DMIC1_MAP | | ||
142 | BYT_RT5640_DMIC_EN), | 369 | BYT_RT5640_DMIC_EN), |
143 | }, | 370 | }, |
144 | { | 371 | { |
145 | .callback = byt_rt5640_quirk_cb, | 372 | .callback = byt_rt5640_quirk_cb, |
146 | .matches = { | 373 | .matches = { |
147 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | 374 | DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"), |
148 | DMI_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"), | 375 | DMI_MATCH(DMI_BOARD_NAME, "tPAD"), |
149 | }, | 376 | }, |
150 | .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, | 377 | .driver_data = (unsigned long *)(BYT_RT5640_IN3_MAP | |
378 | BYT_RT5640_MCLK_EN | | ||
379 | BYT_RT5640_SSP0_AIF1), | ||
380 | }, | ||
381 | { | ||
382 | .callback = byt_rt5640_quirk_cb, | ||
383 | .matches = { | ||
384 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | ||
385 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), | ||
386 | }, | ||
387 | .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP | | ||
388 | BYT_RT5640_MCLK_EN | | ||
389 | BYT_RT5640_SSP0_AIF1), | ||
390 | |||
151 | }, | 391 | }, |
152 | {} | 392 | {} |
153 | }; | 393 | }; |
@@ -158,13 +398,18 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) | |||
158 | struct snd_soc_codec *codec = runtime->codec; | 398 | struct snd_soc_codec *codec = runtime->codec; |
159 | struct snd_soc_card *card = runtime->card; | 399 | struct snd_soc_card *card = runtime->card; |
160 | const struct snd_soc_dapm_route *custom_map; | 400 | const struct snd_soc_dapm_route *custom_map; |
401 | struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card); | ||
161 | int num_routes; | 402 | int num_routes; |
162 | 403 | ||
163 | card->dapm.idle_bias_off = true; | 404 | card->dapm.idle_bias_off = true; |
164 | 405 | ||
165 | rt5640_sel_asrc_clk_src(codec, | 406 | rt5640_sel_asrc_clk_src(codec, |
166 | RT5640_DA_STEREO_FILTER | | 407 | RT5640_DA_STEREO_FILTER | |
167 | RT5640_AD_STEREO_FILTER, | 408 | RT5640_DA_MONO_L_FILTER | |
409 | RT5640_DA_MONO_R_FILTER | | ||
410 | RT5640_AD_STEREO_FILTER | | ||
411 | RT5640_AD_MONO_L_FILTER | | ||
412 | RT5640_AD_MONO_R_FILTER, | ||
168 | RT5640_CLK_SEL_ASRC); | 413 | RT5640_CLK_SEL_ASRC); |
169 | 414 | ||
170 | ret = snd_soc_add_card_controls(card, byt_rt5640_controls, | 415 | ret = snd_soc_add_card_controls(card, byt_rt5640_controls, |
@@ -179,6 +424,10 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) | |||
179 | custom_map = byt_rt5640_intmic_in1_map; | 424 | custom_map = byt_rt5640_intmic_in1_map; |
180 | num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map); | 425 | num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map); |
181 | break; | 426 | break; |
427 | case BYT_RT5640_IN3_MAP: | ||
428 | custom_map = byt_rt5640_intmic_in3_map; | ||
429 | num_routes = ARRAY_SIZE(byt_rt5640_intmic_in3_map); | ||
430 | break; | ||
182 | case BYT_RT5640_DMIC2_MAP: | 431 | case BYT_RT5640_DMIC2_MAP: |
183 | custom_map = byt_rt5640_intmic_dmic2_map; | 432 | custom_map = byt_rt5640_intmic_dmic2_map; |
184 | num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map); | 433 | num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map); |
@@ -192,6 +441,43 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) | |||
192 | if (ret) | 441 | if (ret) |
193 | return ret; | 442 | return ret; |
194 | 443 | ||
444 | if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) { | ||
445 | ret = snd_soc_dapm_add_routes(&card->dapm, | ||
446 | byt_rt5640_ssp2_aif2_map, | ||
447 | ARRAY_SIZE(byt_rt5640_ssp2_aif2_map)); | ||
448 | } else if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) { | ||
449 | ret = snd_soc_dapm_add_routes(&card->dapm, | ||
450 | byt_rt5640_ssp0_aif1_map, | ||
451 | ARRAY_SIZE(byt_rt5640_ssp0_aif1_map)); | ||
452 | } else if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2) { | ||
453 | ret = snd_soc_dapm_add_routes(&card->dapm, | ||
454 | byt_rt5640_ssp0_aif2_map, | ||
455 | ARRAY_SIZE(byt_rt5640_ssp0_aif2_map)); | ||
456 | } else { | ||
457 | ret = snd_soc_dapm_add_routes(&card->dapm, | ||
458 | byt_rt5640_ssp2_aif1_map, | ||
459 | ARRAY_SIZE(byt_rt5640_ssp2_aif1_map)); | ||
460 | } | ||
461 | if (ret) | ||
462 | return ret; | ||
463 | |||
464 | if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) { | ||
465 | ret = snd_soc_dapm_add_routes(&card->dapm, | ||
466 | byt_rt5640_mono_spk_map, | ||
467 | ARRAY_SIZE(byt_rt5640_mono_spk_map)); | ||
468 | } else { | ||
469 | ret = snd_soc_dapm_add_routes(&card->dapm, | ||
470 | byt_rt5640_stereo_spk_map, | ||
471 | ARRAY_SIZE(byt_rt5640_stereo_spk_map)); | ||
472 | } | ||
473 | if (ret) | ||
474 | return ret; | ||
475 | |||
476 | if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) { | ||
477 | snd_soc_update_bits(codec, RT5640_IN1_IN2, RT5640_IN_DF1, | ||
478 | RT5640_IN_DF1); | ||
479 | } | ||
480 | |||
195 | if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) { | 481 | if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) { |
196 | ret = rt5640_dmic_enable(codec, 0, 0); | 482 | ret = rt5640_dmic_enable(codec, 0, 0); |
197 | if (ret) | 483 | if (ret) |
@@ -201,6 +487,30 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) | |||
201 | snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); | 487 | snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); |
202 | snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); | 488 | snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); |
203 | 489 | ||
490 | if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) { | ||
491 | /* | ||
492 | * The firmware might enable the clock at | ||
493 | * boot (this information may or may not | ||
494 | * be reflected in the enable clock register). | ||
495 | * To change the rate we must disable the clock | ||
496 | * first to cover these cases. Due to common | ||
497 | * clock framework restrictions that do not allow | ||
498 | * to disable a clock that has not been enabled, | ||
499 | * we need to enable the clock first. | ||
500 | */ | ||
501 | ret = clk_prepare_enable(priv->mclk); | ||
502 | if (!ret) | ||
503 | clk_disable_unprepare(priv->mclk); | ||
504 | |||
505 | if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) | ||
506 | ret = clk_set_rate(priv->mclk, 25000000); | ||
507 | else | ||
508 | ret = clk_set_rate(priv->mclk, 19200000); | ||
509 | |||
510 | if (ret) | ||
511 | dev_err(card->dev, "unable to set MCLK rate\n"); | ||
512 | } | ||
513 | |||
204 | return ret; | 514 | return ret; |
205 | } | 515 | } |
206 | 516 | ||
@@ -221,34 +531,63 @@ static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd, | |||
221 | SNDRV_PCM_HW_PARAM_CHANNELS); | 531 | SNDRV_PCM_HW_PARAM_CHANNELS); |
222 | int ret; | 532 | int ret; |
223 | 533 | ||
224 | /* The DSP will covert the FE rate to 48k, stereo, 24bits */ | 534 | /* The DSP will covert the FE rate to 48k, stereo */ |
225 | rate->min = rate->max = 48000; | 535 | rate->min = rate->max = 48000; |
226 | channels->min = channels->max = 2; | 536 | channels->min = channels->max = 2; |
227 | 537 | ||
228 | /* set SSP2 to 24-bit */ | 538 | if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || |
229 | params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); | 539 | (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { |
540 | |||
541 | /* set SSP0 to 16-bit */ | ||
542 | params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); | ||
543 | |||
544 | /* | ||
545 | * Default mode for SSP configuration is TDM 4 slot, override config | ||
546 | * with explicit setting to I2S 2ch 16-bit. The word length is set with | ||
547 | * dai_set_tdm_slot() since there is no other API exposed | ||
548 | */ | ||
549 | ret = snd_soc_dai_set_fmt(rtd->cpu_dai, | ||
550 | SND_SOC_DAIFMT_I2S | | ||
551 | SND_SOC_DAIFMT_NB_IF | | ||
552 | SND_SOC_DAIFMT_CBS_CFS | ||
553 | ); | ||
554 | if (ret < 0) { | ||
555 | dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); | ||
556 | return ret; | ||
557 | } | ||
230 | 558 | ||
231 | /* | 559 | ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16); |
232 | * Default mode for SSP configuration is TDM 4 slot, override config | 560 | if (ret < 0) { |
233 | * with explicit setting to I2S 2ch 24-bit. The word length is set with | 561 | dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); |
234 | * dai_set_tdm_slot() since there is no other API exposed | 562 | return ret; |
235 | */ | 563 | } |
236 | ret = snd_soc_dai_set_fmt(rtd->cpu_dai, | ||
237 | SND_SOC_DAIFMT_I2S | | ||
238 | SND_SOC_DAIFMT_NB_IF | | ||
239 | SND_SOC_DAIFMT_CBS_CFS | ||
240 | ); | ||
241 | if (ret < 0) { | ||
242 | dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); | ||
243 | return ret; | ||
244 | } | ||
245 | 564 | ||
246 | ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); | 565 | } else { |
247 | if (ret < 0) { | 566 | |
248 | dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); | 567 | /* set SSP2 to 24-bit */ |
249 | return ret; | 568 | params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); |
250 | } | 569 | |
570 | /* | ||
571 | * Default mode for SSP configuration is TDM 4 slot, override config | ||
572 | * with explicit setting to I2S 2ch 24-bit. The word length is set with | ||
573 | * dai_set_tdm_slot() since there is no other API exposed | ||
574 | */ | ||
575 | ret = snd_soc_dai_set_fmt(rtd->cpu_dai, | ||
576 | SND_SOC_DAIFMT_I2S | | ||
577 | SND_SOC_DAIFMT_NB_IF | | ||
578 | SND_SOC_DAIFMT_CBS_CFS | ||
579 | ); | ||
580 | if (ret < 0) { | ||
581 | dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); | ||
582 | return ret; | ||
583 | } | ||
251 | 584 | ||
585 | ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); | ||
586 | if (ret < 0) { | ||
587 | dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); | ||
588 | return ret; | ||
589 | } | ||
590 | } | ||
252 | return 0; | 591 | return 0; |
253 | } | 592 | } |
254 | 593 | ||
@@ -305,10 +644,10 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { | |||
305 | { | 644 | { |
306 | .name = "SSP2-Codec", | 645 | .name = "SSP2-Codec", |
307 | .id = 1, | 646 | .id = 1, |
308 | .cpu_dai_name = "ssp2-port", | 647 | .cpu_dai_name = "ssp2-port", /* overwritten for ssp0 routing */ |
309 | .platform_name = "sst-mfld-platform", | 648 | .platform_name = "sst-mfld-platform", |
310 | .no_pcm = 1, | 649 | .no_pcm = 1, |
311 | .codec_dai_name = "rt5640-aif1", | 650 | .codec_dai_name = "rt5640-aif1", /* changed w/ quirk */ |
312 | .codec_name = "i2c-10EC5640:00", /* overwritten with HID */ | 651 | .codec_name = "i2c-10EC5640:00", /* overwritten with HID */ |
313 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 652 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
314 | | SND_SOC_DAIFMT_CBS_CFS, | 653 | | SND_SOC_DAIFMT_CBS_CFS, |
@@ -335,6 +674,21 @@ static struct snd_soc_card byt_rt5640_card = { | |||
335 | }; | 674 | }; |
336 | 675 | ||
337 | static char byt_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */ | 676 | static char byt_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */ |
677 | static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ | ||
678 | static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ | ||
679 | |||
680 | static bool is_valleyview(void) | ||
681 | { | ||
682 | static const struct x86_cpu_id cpu_ids[] = { | ||
683 | { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */ | ||
684 | {} | ||
685 | }; | ||
686 | |||
687 | if (!x86_match_cpu(cpu_ids)) | ||
688 | return false; | ||
689 | return true; | ||
690 | } | ||
691 | |||
338 | 692 | ||
339 | static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) | 693 | static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) |
340 | { | 694 | { |
@@ -343,10 +697,16 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) | |||
343 | const char *i2c_name = NULL; | 697 | const char *i2c_name = NULL; |
344 | int i; | 698 | int i; |
345 | int dai_index; | 699 | int dai_index; |
700 | struct byt_rt5640_private *priv; | ||
701 | |||
702 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); | ||
703 | if (!priv) | ||
704 | return -ENOMEM; | ||
346 | 705 | ||
347 | /* register the soc card */ | 706 | /* register the soc card */ |
348 | byt_rt5640_card.dev = &pdev->dev; | 707 | byt_rt5640_card.dev = &pdev->dev; |
349 | mach = byt_rt5640_card.dev->platform_data; | 708 | mach = byt_rt5640_card.dev->platform_data; |
709 | snd_soc_card_set_drvdata(&byt_rt5640_card, priv); | ||
350 | 710 | ||
351 | /* fix index of codec dai */ | 711 | /* fix index of codec dai */ |
352 | dai_index = MERR_DPCM_COMPR + 1; | 712 | dai_index = MERR_DPCM_COMPR + 1; |
@@ -366,8 +726,57 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) | |||
366 | byt_rt5640_dais[dai_index].codec_name = byt_rt5640_codec_name; | 726 | byt_rt5640_dais[dai_index].codec_name = byt_rt5640_codec_name; |
367 | } | 727 | } |
368 | 728 | ||
729 | /* | ||
730 | * swap SSP0 if bytcr is detected | ||
731 | * (will be overridden if DMI quirk is detected) | ||
732 | */ | ||
733 | if (is_valleyview()) { | ||
734 | struct sst_platform_info *p_info = mach->pdata; | ||
735 | const struct sst_res_info *res_info = p_info->res_info; | ||
736 | |||
737 | /* TODO: use CHAN package info from BIOS to detect AIF1/AIF2 */ | ||
738 | if (res_info->acpi_ipc_irq_index == 0) { | ||
739 | byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; | ||
740 | } | ||
741 | } | ||
742 | |||
369 | /* check quirks before creating card */ | 743 | /* check quirks before creating card */ |
370 | dmi_check_system(byt_rt5640_quirk_table); | 744 | dmi_check_system(byt_rt5640_quirk_table); |
745 | log_quirks(&pdev->dev); | ||
746 | |||
747 | if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) || | ||
748 | (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { | ||
749 | |||
750 | /* fixup codec aif name */ | ||
751 | snprintf(byt_rt5640_codec_aif_name, | ||
752 | sizeof(byt_rt5640_codec_aif_name), | ||
753 | "%s", "rt5640-aif2"); | ||
754 | |||
755 | byt_rt5640_dais[dai_index].codec_dai_name = | ||
756 | byt_rt5640_codec_aif_name; | ||
757 | } | ||
758 | |||
759 | if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || | ||
760 | (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { | ||
761 | |||
762 | /* fixup cpu dai name name */ | ||
763 | snprintf(byt_rt5640_cpu_dai_name, | ||
764 | sizeof(byt_rt5640_cpu_dai_name), | ||
765 | "%s", "ssp0-port"); | ||
766 | |||
767 | byt_rt5640_dais[dai_index].cpu_dai_name = | ||
768 | byt_rt5640_cpu_dai_name; | ||
769 | } | ||
770 | |||
771 | if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && (is_valleyview())) { | ||
772 | priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); | ||
773 | if (IS_ERR(priv->mclk)) { | ||
774 | dev_err(&pdev->dev, | ||
775 | "Failed to get MCLK from pmc_plt_clk_3: %ld\n", | ||
776 | PTR_ERR(priv->mclk)); | ||
777 | return PTR_ERR(priv->mclk); | ||
778 | } | ||
779 | } | ||
371 | 780 | ||
372 | ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); | 781 | ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); |
373 | 782 | ||
diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c index 2c5eda14d510..1285cc597b6b 100644 --- a/sound/soc/intel/common/sst-acpi.c +++ b/sound/soc/intel/common/sst-acpi.c | |||
@@ -199,6 +199,7 @@ static struct sst_acpi_desc sst_acpi_haswell_desc = { | |||
199 | 199 | ||
200 | static struct sst_acpi_mach broadwell_machines[] = { | 200 | static struct sst_acpi_mach broadwell_machines[] = { |
201 | { "INT343A", "broadwell-audio", "intel/IntcSST2.bin", NULL, NULL, NULL }, | 201 | { "INT343A", "broadwell-audio", "intel/IntcSST2.bin", NULL, NULL, NULL }, |
202 | { "RT5677CE", "bdw-rt5677", "intel/IntcSST2.bin", NULL, NULL, NULL }, | ||
202 | {} | 203 | {} |
203 | }; | 204 | }; |
204 | 205 | ||
diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 2663781278aa..1d251d59bcb9 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "../common/sst-dsp.h" | 23 | #include "../common/sst-dsp.h" |
24 | #include "../common/sst-dsp-priv.h" | 24 | #include "../common/sst-dsp-priv.h" |
25 | #include "skl-sst-ipc.h" | 25 | #include "skl-sst-ipc.h" |
26 | #include "skl-tplg-interface.h" | ||
26 | 27 | ||
27 | #define BXT_BASEFW_TIMEOUT 3000 | 28 | #define BXT_BASEFW_TIMEOUT 3000 |
28 | #define BXT_INIT_TIMEOUT 500 | 29 | #define BXT_INIT_TIMEOUT 500 |
@@ -40,11 +41,73 @@ | |||
40 | #define BXT_INSTANCE_ID 0 | 41 | #define BXT_INSTANCE_ID 0 |
41 | #define BXT_BASE_FW_MODULE_ID 0 | 42 | #define BXT_BASE_FW_MODULE_ID 0 |
42 | 43 | ||
44 | #define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000 | ||
45 | |||
43 | static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) | 46 | static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) |
44 | { | 47 | { |
45 | return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); | 48 | return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); |
46 | } | 49 | } |
47 | 50 | ||
51 | static int | ||
52 | bxt_load_library(struct sst_dsp *ctx, struct skl_dfw_manifest *minfo) | ||
53 | { | ||
54 | struct snd_dma_buffer dmab; | ||
55 | struct skl_sst *skl = ctx->thread_context; | ||
56 | const struct firmware *fw = NULL; | ||
57 | struct firmware stripped_fw; | ||
58 | int ret = 0, i, dma_id, stream_tag; | ||
59 | |||
60 | /* library indices start from 1 to N. 0 represents base FW */ | ||
61 | for (i = 1; i < minfo->lib_count; i++) { | ||
62 | ret = request_firmware(&fw, minfo->lib[i].name, ctx->dev); | ||
63 | if (ret < 0) { | ||
64 | dev_err(ctx->dev, "Request lib %s failed:%d\n", | ||
65 | minfo->lib[i].name, ret); | ||
66 | return ret; | ||
67 | } | ||
68 | |||
69 | if (skl->is_first_boot) { | ||
70 | ret = snd_skl_parse_uuids(ctx, fw, | ||
71 | BXT_ADSP_FW_BIN_HDR_OFFSET, i); | ||
72 | if (ret < 0) | ||
73 | goto load_library_failed; | ||
74 | } | ||
75 | |||
76 | stripped_fw.data = fw->data; | ||
77 | stripped_fw.size = fw->size; | ||
78 | skl_dsp_strip_extended_manifest(&stripped_fw); | ||
79 | |||
80 | stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, | ||
81 | stripped_fw.size, &dmab); | ||
82 | if (stream_tag <= 0) { | ||
83 | dev_err(ctx->dev, "Lib prepare DMA err: %x\n", | ||
84 | stream_tag); | ||
85 | ret = stream_tag; | ||
86 | goto load_library_failed; | ||
87 | } | ||
88 | |||
89 | dma_id = stream_tag - 1; | ||
90 | memcpy(dmab.area, stripped_fw.data, stripped_fw.size); | ||
91 | |||
92 | ctx->dsp_ops.trigger(ctx->dev, true, stream_tag); | ||
93 | ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i); | ||
94 | if (ret < 0) | ||
95 | dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n", | ||
96 | minfo->lib[i].name, ret); | ||
97 | |||
98 | ctx->dsp_ops.trigger(ctx->dev, false, stream_tag); | ||
99 | ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag); | ||
100 | release_firmware(fw); | ||
101 | fw = NULL; | ||
102 | } | ||
103 | |||
104 | return ret; | ||
105 | |||
106 | load_library_failed: | ||
107 | release_firmware(fw); | ||
108 | return ret; | ||
109 | } | ||
110 | |||
48 | /* | 111 | /* |
49 | * First boot sequence has some extra steps. Core 0 waits for power | 112 | * First boot sequence has some extra steps. Core 0 waits for power |
50 | * status on core 1, so power up core 1 also momentarily, keep it in | 113 | * status on core 1, so power up core 1 also momentarily, keep it in |
@@ -157,8 +220,6 @@ static int sst_transfer_fw_host_dma(struct sst_dsp *ctx) | |||
157 | return ret; | 220 | return ret; |
158 | } | 221 | } |
159 | 222 | ||
160 | #define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000 | ||
161 | |||
162 | static int bxt_load_base_firmware(struct sst_dsp *ctx) | 223 | static int bxt_load_base_firmware(struct sst_dsp *ctx) |
163 | { | 224 | { |
164 | struct firmware stripped_fw; | 225 | struct firmware stripped_fw; |
@@ -175,9 +236,12 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx) | |||
175 | if (ctx->fw == NULL) | 236 | if (ctx->fw == NULL) |
176 | goto sst_load_base_firmware_failed; | 237 | goto sst_load_base_firmware_failed; |
177 | 238 | ||
178 | ret = snd_skl_parse_uuids(ctx, BXT_ADSP_FW_BIN_HDR_OFFSET); | 239 | /* prase uuids on first boot */ |
179 | if (ret < 0) | 240 | if (skl->is_first_boot) { |
180 | goto sst_load_base_firmware_failed; | 241 | ret = snd_skl_parse_uuids(ctx, ctx->fw, BXT_ADSP_FW_BIN_HDR_OFFSET, 0); |
242 | if (ret < 0) | ||
243 | goto sst_load_base_firmware_failed; | ||
244 | } | ||
181 | 245 | ||
182 | stripped_fw.data = ctx->fw->data; | 246 | stripped_fw.data = ctx->fw->data; |
183 | stripped_fw.size = ctx->fw->size; | 247 | stripped_fw.size = ctx->fw->size; |
@@ -230,12 +294,23 @@ static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) | |||
230 | int ret; | 294 | int ret; |
231 | struct skl_ipc_dxstate_info dx; | 295 | struct skl_ipc_dxstate_info dx; |
232 | unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); | 296 | unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); |
297 | struct skl_dfw_manifest *minfo = &skl->manifest; | ||
233 | 298 | ||
234 | if (skl->fw_loaded == false) { | 299 | if (skl->fw_loaded == false) { |
235 | skl->boot_complete = false; | 300 | skl->boot_complete = false; |
236 | ret = bxt_load_base_firmware(ctx); | 301 | ret = bxt_load_base_firmware(ctx); |
237 | if (ret < 0) | 302 | if (ret < 0) { |
238 | dev_err(ctx->dev, "reload fw failed: %d\n", ret); | 303 | dev_err(ctx->dev, "reload fw failed: %d\n", ret); |
304 | return ret; | ||
305 | } | ||
306 | |||
307 | if (minfo->lib_count > 1) { | ||
308 | ret = bxt_load_library(ctx, minfo); | ||
309 | if (ret < 0) { | ||
310 | dev_err(ctx->dev, "reload libs failed: %d\n", ret); | ||
311 | return ret; | ||
312 | } | ||
313 | } | ||
239 | return ret; | 314 | return ret; |
240 | } | 315 | } |
241 | 316 | ||
@@ -329,7 +404,7 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) | |||
329 | 404 | ||
330 | ret = skl_dsp_disable_core(ctx, core_mask); | 405 | ret = skl_dsp_disable_core(ctx, core_mask); |
331 | if (ret < 0) { | 406 | if (ret < 0) { |
332 | dev_err(ctx->dev, "Failed to disable core %d", ret); | 407 | dev_err(ctx->dev, "Failed to disable core %d\n", ret); |
333 | return ret; | 408 | return ret; |
334 | } | 409 | } |
335 | skl->cores.state[core_id] = SKL_DSP_RESET; | 410 | skl->cores.state[core_id] = SKL_DSP_RESET; |
@@ -341,6 +416,7 @@ static struct skl_dsp_fw_ops bxt_fw_ops = { | |||
341 | .set_state_D3 = bxt_set_dsp_D3, | 416 | .set_state_D3 = bxt_set_dsp_D3, |
342 | .load_fw = bxt_load_base_firmware, | 417 | .load_fw = bxt_load_base_firmware, |
343 | .get_fw_errcode = bxt_get_errorcode, | 418 | .get_fw_errcode = bxt_get_errorcode, |
419 | .load_library = bxt_load_library, | ||
344 | }; | 420 | }; |
345 | 421 | ||
346 | static struct sst_ops skl_ops = { | 422 | static struct sst_ops skl_ops = { |
@@ -397,22 +473,40 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, | |||
397 | skl->cores.count = 2; | 473 | skl->cores.count = 2; |
398 | skl->boot_complete = false; | 474 | skl->boot_complete = false; |
399 | init_waitqueue_head(&skl->boot_wait); | 475 | init_waitqueue_head(&skl->boot_wait); |
476 | skl->is_first_boot = true; | ||
477 | |||
478 | if (dsp) | ||
479 | *dsp = skl; | ||
480 | |||
481 | return 0; | ||
482 | } | ||
483 | EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); | ||
484 | |||
485 | int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx) | ||
486 | { | ||
487 | int ret; | ||
488 | struct sst_dsp *sst = ctx->dsp; | ||
400 | 489 | ||
401 | ret = sst->fw_ops.load_fw(sst); | 490 | ret = sst->fw_ops.load_fw(sst); |
402 | if (ret < 0) { | 491 | if (ret < 0) { |
403 | dev_err(dev, "Load base fw failed: %x", ret); | 492 | dev_err(dev, "Load base fw failed: %x\n", ret); |
404 | return ret; | 493 | return ret; |
405 | } | 494 | } |
406 | 495 | ||
407 | skl_dsp_init_core_state(sst); | 496 | skl_dsp_init_core_state(sst); |
408 | 497 | ||
409 | if (dsp) | 498 | if (ctx->manifest.lib_count > 1) { |
410 | *dsp = skl; | 499 | ret = sst->fw_ops.load_library(sst, &ctx->manifest); |
500 | if (ret < 0) { | ||
501 | dev_err(dev, "Load Library failed : %x\n", ret); | ||
502 | return ret; | ||
503 | } | ||
504 | } | ||
505 | ctx->is_first_boot = false; | ||
411 | 506 | ||
412 | return 0; | 507 | return 0; |
413 | } | 508 | } |
414 | EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); | 509 | EXPORT_SYMBOL_GPL(bxt_sst_init_fw); |
415 | |||
416 | 510 | ||
417 | void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) | 511 | void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) |
418 | { | 512 | { |
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 44ab595ce21a..805b7f2173f3 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c | |||
@@ -203,32 +203,35 @@ static const struct skl_dsp_ops dsp_ops[] = { | |||
203 | .id = 0x9d70, | 203 | .id = 0x9d70, |
204 | .loader_ops = skl_get_loader_ops, | 204 | .loader_ops = skl_get_loader_ops, |
205 | .init = skl_sst_dsp_init, | 205 | .init = skl_sst_dsp_init, |
206 | .init_fw = skl_sst_init_fw, | ||
206 | .cleanup = skl_sst_dsp_cleanup | 207 | .cleanup = skl_sst_dsp_cleanup |
207 | }, | 208 | }, |
208 | { | 209 | { |
209 | .id = 0x9d71, | 210 | .id = 0x9d71, |
210 | .loader_ops = skl_get_loader_ops, | 211 | .loader_ops = skl_get_loader_ops, |
211 | .init = skl_sst_dsp_init, | 212 | .init = skl_sst_dsp_init, |
213 | .init_fw = skl_sst_init_fw, | ||
212 | .cleanup = skl_sst_dsp_cleanup | 214 | .cleanup = skl_sst_dsp_cleanup |
213 | }, | 215 | }, |
214 | { | 216 | { |
215 | .id = 0x5a98, | 217 | .id = 0x5a98, |
216 | .loader_ops = bxt_get_loader_ops, | 218 | .loader_ops = bxt_get_loader_ops, |
217 | .init = bxt_sst_dsp_init, | 219 | .init = bxt_sst_dsp_init, |
220 | .init_fw = bxt_sst_init_fw, | ||
218 | .cleanup = bxt_sst_dsp_cleanup | 221 | .cleanup = bxt_sst_dsp_cleanup |
219 | }, | 222 | }, |
220 | }; | 223 | }; |
221 | 224 | ||
222 | static int skl_get_dsp_ops(int pci_id) | 225 | const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) |
223 | { | 226 | { |
224 | int i; | 227 | int i; |
225 | 228 | ||
226 | for (i = 0; i < ARRAY_SIZE(dsp_ops); i++) { | 229 | for (i = 0; i < ARRAY_SIZE(dsp_ops); i++) { |
227 | if (dsp_ops[i].id == pci_id) | 230 | if (dsp_ops[i].id == pci_id) |
228 | return i; | 231 | return &dsp_ops[i]; |
229 | } | 232 | } |
230 | 233 | ||
231 | return -EINVAL; | 234 | return NULL; |
232 | } | 235 | } |
233 | 236 | ||
234 | int skl_init_dsp(struct skl *skl) | 237 | int skl_init_dsp(struct skl *skl) |
@@ -238,7 +241,8 @@ int skl_init_dsp(struct skl *skl) | |||
238 | struct hdac_bus *bus = ebus_to_hbus(ebus); | 241 | struct hdac_bus *bus = ebus_to_hbus(ebus); |
239 | struct skl_dsp_loader_ops loader_ops; | 242 | struct skl_dsp_loader_ops loader_ops; |
240 | int irq = bus->irq; | 243 | int irq = bus->irq; |
241 | int ret, index; | 244 | const struct skl_dsp_ops *ops; |
245 | int ret; | ||
242 | 246 | ||
243 | /* enable ppcap interrupt */ | 247 | /* enable ppcap interrupt */ |
244 | snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true); | 248 | snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true); |
@@ -251,18 +255,18 @@ int skl_init_dsp(struct skl *skl) | |||
251 | return -ENXIO; | 255 | return -ENXIO; |
252 | } | 256 | } |
253 | 257 | ||
254 | index = skl_get_dsp_ops(skl->pci->device); | 258 | ops = skl_get_dsp_ops(skl->pci->device); |
255 | if (index < 0) | 259 | if (!ops) |
256 | return -EINVAL; | 260 | return -EIO; |
257 | 261 | ||
258 | loader_ops = dsp_ops[index].loader_ops(); | 262 | loader_ops = ops->loader_ops(); |
259 | ret = dsp_ops[index].init(bus->dev, mmio_base, irq, | 263 | ret = ops->init(bus->dev, mmio_base, irq, |
260 | skl->fw_name, loader_ops, &skl->skl_sst); | 264 | skl->fw_name, loader_ops, |
265 | &skl->skl_sst); | ||
261 | 266 | ||
262 | if (ret < 0) | 267 | if (ret < 0) |
263 | return ret; | 268 | return ret; |
264 | 269 | ||
265 | skl_dsp_enable_notification(skl->skl_sst, false); | ||
266 | dev_dbg(bus->dev, "dsp registration status=%d\n", ret); | 270 | dev_dbg(bus->dev, "dsp registration status=%d\n", ret); |
267 | 271 | ||
268 | return ret; | 272 | return ret; |
@@ -273,16 +277,16 @@ int skl_free_dsp(struct skl *skl) | |||
273 | struct hdac_ext_bus *ebus = &skl->ebus; | 277 | struct hdac_ext_bus *ebus = &skl->ebus; |
274 | struct hdac_bus *bus = ebus_to_hbus(ebus); | 278 | struct hdac_bus *bus = ebus_to_hbus(ebus); |
275 | struct skl_sst *ctx = skl->skl_sst; | 279 | struct skl_sst *ctx = skl->skl_sst; |
276 | int index; | 280 | const struct skl_dsp_ops *ops; |
277 | 281 | ||
278 | /* disable ppcap interrupt */ | 282 | /* disable ppcap interrupt */ |
279 | snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false); | 283 | snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false); |
280 | 284 | ||
281 | index = skl_get_dsp_ops(skl->pci->device); | 285 | ops = skl_get_dsp_ops(skl->pci->device); |
282 | if (index < 0) | 286 | if (!ops) |
283 | return -EIO; | 287 | return -EIO; |
284 | 288 | ||
285 | dsp_ops[index].cleanup(bus->dev, ctx); | 289 | ops->cleanup(bus->dev, ctx); |
286 | 290 | ||
287 | if (ctx->dsp->addr.lpe) | 291 | if (ctx->dsp->addr.lpe) |
288 | iounmap(ctx->dsp->addr.lpe); | 292 | iounmap(ctx->dsp->addr.lpe); |
@@ -296,7 +300,7 @@ int skl_suspend_dsp(struct skl *skl) | |||
296 | int ret; | 300 | int ret; |
297 | 301 | ||
298 | /* if ppcap is not supported return 0 */ | 302 | /* if ppcap is not supported return 0 */ |
299 | if (!skl->ebus.ppcap) | 303 | if (!skl->ebus.bus.ppcap) |
300 | return 0; | 304 | return 0; |
301 | 305 | ||
302 | ret = skl_dsp_sleep(ctx->dsp); | 306 | ret = skl_dsp_sleep(ctx->dsp); |
@@ -316,13 +320,17 @@ int skl_resume_dsp(struct skl *skl) | |||
316 | int ret; | 320 | int ret; |
317 | 321 | ||
318 | /* if ppcap is not supported return 0 */ | 322 | /* if ppcap is not supported return 0 */ |
319 | if (!skl->ebus.ppcap) | 323 | if (!skl->ebus.bus.ppcap) |
320 | return 0; | 324 | return 0; |
321 | 325 | ||
322 | /* enable ppcap interrupt */ | 326 | /* enable ppcap interrupt */ |
323 | snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true); | 327 | snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true); |
324 | snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true); | 328 | snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true); |
325 | 329 | ||
330 | /* check if DSP 1st boot is done */ | ||
331 | if (skl->skl_sst->is_first_boot == true) | ||
332 | return 0; | ||
333 | |||
326 | ret = skl_dsp_wake(ctx->dsp); | 334 | ret = skl_dsp_wake(ctx->dsp); |
327 | if (ret < 0) | 335 | if (ret < 0) |
328 | return ret; | 336 | return ret; |
@@ -672,6 +680,7 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx, | |||
672 | return param_size; | 680 | return param_size; |
673 | 681 | ||
674 | case SKL_MODULE_TYPE_BASE_OUTFMT: | 682 | case SKL_MODULE_TYPE_BASE_OUTFMT: |
683 | case SKL_MODULE_TYPE_KPB: | ||
675 | return sizeof(struct skl_base_outfmt_cfg); | 684 | return sizeof(struct skl_base_outfmt_cfg); |
676 | 685 | ||
677 | default: | 686 | default: |
@@ -725,6 +734,7 @@ static int skl_set_module_format(struct skl_sst *ctx, | |||
725 | break; | 734 | break; |
726 | 735 | ||
727 | case SKL_MODULE_TYPE_BASE_OUTFMT: | 736 | case SKL_MODULE_TYPE_BASE_OUTFMT: |
737 | case SKL_MODULE_TYPE_KPB: | ||
728 | skl_set_base_outfmt_format(ctx, module_config, *param_data); | 738 | skl_set_base_outfmt_format(ctx, module_config, *param_data); |
729 | break; | 739 | break; |
730 | 740 | ||
@@ -779,6 +789,7 @@ static int skl_alloc_queue(struct skl_module_pin *mpin, | |||
779 | mpin[i].in_use = true; | 789 | mpin[i].in_use = true; |
780 | mpin[i].id.module_id = id.module_id; | 790 | mpin[i].id.module_id = id.module_id; |
781 | mpin[i].id.instance_id = id.instance_id; | 791 | mpin[i].id.instance_id = id.instance_id; |
792 | mpin[i].id.pvt_id = id.pvt_id; | ||
782 | mpin[i].tgt_mcfg = tgt_cfg; | 793 | mpin[i].tgt_mcfg = tgt_cfg; |
783 | return i; | 794 | return i; |
784 | } | 795 | } |
@@ -802,6 +813,7 @@ static void skl_free_queue(struct skl_module_pin *mpin, int q_index) | |||
802 | mpin[q_index].in_use = false; | 813 | mpin[q_index].in_use = false; |
803 | mpin[q_index].id.module_id = 0; | 814 | mpin[q_index].id.module_id = 0; |
804 | mpin[q_index].id.instance_id = 0; | 815 | mpin[q_index].id.instance_id = 0; |
816 | mpin[q_index].id.pvt_id = 0; | ||
805 | } | 817 | } |
806 | mpin[q_index].pin_state = SKL_PIN_UNBIND; | 818 | mpin[q_index].pin_state = SKL_PIN_UNBIND; |
807 | mpin[q_index].tgt_mcfg = NULL; | 819 | mpin[q_index].tgt_mcfg = NULL; |
@@ -842,7 +854,7 @@ int skl_init_module(struct skl_sst *ctx, | |||
842 | struct skl_ipc_init_instance_msg msg; | 854 | struct skl_ipc_init_instance_msg msg; |
843 | 855 | ||
844 | dev_dbg(ctx->dev, "%s: module_id = %d instance=%d\n", __func__, | 856 | dev_dbg(ctx->dev, "%s: module_id = %d instance=%d\n", __func__, |
845 | mconfig->id.module_id, mconfig->id.instance_id); | 857 | mconfig->id.module_id, mconfig->id.pvt_id); |
846 | 858 | ||
847 | if (mconfig->pipe->state != SKL_PIPE_CREATED) { | 859 | if (mconfig->pipe->state != SKL_PIPE_CREATED) { |
848 | dev_err(ctx->dev, "Pipe not created state= %d pipe_id= %d\n", | 860 | dev_err(ctx->dev, "Pipe not created state= %d pipe_id= %d\n", |
@@ -858,10 +870,11 @@ int skl_init_module(struct skl_sst *ctx, | |||
858 | } | 870 | } |
859 | 871 | ||
860 | msg.module_id = mconfig->id.module_id; | 872 | msg.module_id = mconfig->id.module_id; |
861 | msg.instance_id = mconfig->id.instance_id; | 873 | msg.instance_id = mconfig->id.pvt_id; |
862 | msg.ppl_instance_id = mconfig->pipe->ppl_id; | 874 | msg.ppl_instance_id = mconfig->pipe->ppl_id; |
863 | msg.param_data_size = module_config_size; | 875 | msg.param_data_size = module_config_size; |
864 | msg.core_id = mconfig->core_id; | 876 | msg.core_id = mconfig->core_id; |
877 | msg.domain = mconfig->domain; | ||
865 | 878 | ||
866 | ret = skl_ipc_init_instance(&ctx->ipc, &msg, param_data); | 879 | ret = skl_ipc_init_instance(&ctx->ipc, &msg, param_data); |
867 | if (ret < 0) { | 880 | if (ret < 0) { |
@@ -878,9 +891,9 @@ static void skl_dump_bind_info(struct skl_sst *ctx, struct skl_module_cfg | |||
878 | *src_module, struct skl_module_cfg *dst_module) | 891 | *src_module, struct skl_module_cfg *dst_module) |
879 | { | 892 | { |
880 | dev_dbg(ctx->dev, "%s: src module_id = %d src_instance=%d\n", | 893 | dev_dbg(ctx->dev, "%s: src module_id = %d src_instance=%d\n", |
881 | __func__, src_module->id.module_id, src_module->id.instance_id); | 894 | __func__, src_module->id.module_id, src_module->id.pvt_id); |
882 | dev_dbg(ctx->dev, "%s: dst_module=%d dst_instacne=%d\n", __func__, | 895 | dev_dbg(ctx->dev, "%s: dst_module=%d dst_instacne=%d\n", __func__, |
883 | dst_module->id.module_id, dst_module->id.instance_id); | 896 | dst_module->id.module_id, dst_module->id.pvt_id); |
884 | 897 | ||
885 | dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n", | 898 | dev_dbg(ctx->dev, "src_module state = %d dst module state = %d\n", |
886 | src_module->m_state, dst_module->m_state); | 899 | src_module->m_state, dst_module->m_state); |
@@ -927,9 +940,9 @@ int skl_unbind_modules(struct skl_sst *ctx, | |||
927 | return 0; | 940 | return 0; |
928 | 941 | ||
929 | msg.module_id = src_mcfg->id.module_id; | 942 | msg.module_id = src_mcfg->id.module_id; |
930 | msg.instance_id = src_mcfg->id.instance_id; | 943 | msg.instance_id = src_mcfg->id.pvt_id; |
931 | msg.dst_module_id = dst_mcfg->id.module_id; | 944 | msg.dst_module_id = dst_mcfg->id.module_id; |
932 | msg.dst_instance_id = dst_mcfg->id.instance_id; | 945 | msg.dst_instance_id = dst_mcfg->id.pvt_id; |
933 | msg.bind = false; | 946 | msg.bind = false; |
934 | 947 | ||
935 | ret = skl_ipc_bind_unbind(&ctx->ipc, &msg); | 948 | ret = skl_ipc_bind_unbind(&ctx->ipc, &msg); |
@@ -988,9 +1001,9 @@ int skl_bind_modules(struct skl_sst *ctx, | |||
988 | msg.src_queue, msg.dst_queue); | 1001 | msg.src_queue, msg.dst_queue); |
989 | 1002 | ||
990 | msg.module_id = src_mcfg->id.module_id; | 1003 | msg.module_id = src_mcfg->id.module_id; |
991 | msg.instance_id = src_mcfg->id.instance_id; | 1004 | msg.instance_id = src_mcfg->id.pvt_id; |
992 | msg.dst_module_id = dst_mcfg->id.module_id; | 1005 | msg.dst_module_id = dst_mcfg->id.module_id; |
993 | msg.dst_instance_id = dst_mcfg->id.instance_id; | 1006 | msg.dst_instance_id = dst_mcfg->id.pvt_id; |
994 | msg.bind = true; | 1007 | msg.bind = true; |
995 | 1008 | ||
996 | ret = skl_ipc_bind_unbind(&ctx->ipc, &msg); | 1009 | ret = skl_ipc_bind_unbind(&ctx->ipc, &msg); |
@@ -1168,7 +1181,7 @@ int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, | |||
1168 | struct skl_ipc_large_config_msg msg; | 1181 | struct skl_ipc_large_config_msg msg; |
1169 | 1182 | ||
1170 | msg.module_id = mcfg->id.module_id; | 1183 | msg.module_id = mcfg->id.module_id; |
1171 | msg.instance_id = mcfg->id.instance_id; | 1184 | msg.instance_id = mcfg->id.pvt_id; |
1172 | msg.param_data_size = size; | 1185 | msg.param_data_size = size; |
1173 | msg.large_param_id = param_id; | 1186 | msg.large_param_id = param_id; |
1174 | 1187 | ||
@@ -1181,7 +1194,7 @@ int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, | |||
1181 | struct skl_ipc_large_config_msg msg; | 1194 | struct skl_ipc_large_config_msg msg; |
1182 | 1195 | ||
1183 | msg.module_id = mcfg->id.module_id; | 1196 | msg.module_id = mcfg->id.module_id; |
1184 | msg.instance_id = mcfg->id.instance_id; | 1197 | msg.instance_id = mcfg->id.pvt_id; |
1185 | msg.param_data_size = size; | 1198 | msg.param_data_size = size; |
1186 | msg.large_param_id = param_id; | 1199 | msg.large_param_id = param_id; |
1187 | 1200 | ||
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 6e05bf8622f7..c7cdcba04c5d 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c | |||
@@ -106,7 +106,7 @@ static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus, | |||
106 | 106 | ||
107 | static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *ebus) | 107 | static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *ebus) |
108 | { | 108 | { |
109 | if (ebus->ppcap) | 109 | if ((ebus_to_hbus(ebus))->ppcap) |
110 | return HDAC_EXT_STREAM_TYPE_HOST; | 110 | return HDAC_EXT_STREAM_TYPE_HOST; |
111 | else | 111 | else |
112 | return HDAC_EXT_STREAM_TYPE_COUPLED; | 112 | return HDAC_EXT_STREAM_TYPE_COUPLED; |
@@ -188,7 +188,7 @@ static int skl_get_format(struct snd_pcm_substream *substream, | |||
188 | struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); | 188 | struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); |
189 | int format_val = 0; | 189 | int format_val = 0; |
190 | 190 | ||
191 | if (ebus->ppcap) { | 191 | if ((ebus_to_hbus(ebus))->ppcap) { |
192 | struct snd_pcm_runtime *runtime = substream->runtime; | 192 | struct snd_pcm_runtime *runtime = substream->runtime; |
193 | 193 | ||
194 | format_val = snd_hdac_calc_stream_format(runtime->rate, | 194 | format_val = snd_hdac_calc_stream_format(runtime->rate, |
@@ -648,7 +648,8 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { | |||
648 | .channels_min = HDA_MONO, | 648 | .channels_min = HDA_MONO, |
649 | .channels_max = HDA_STEREO, | 649 | .channels_max = HDA_STEREO, |
650 | .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, | 650 | .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, |
651 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, | 651 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
652 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, | ||
652 | }, | 653 | }, |
653 | .capture = { | 654 | .capture = { |
654 | .stream_name = "System Capture", | 655 | .stream_name = "System Capture", |
@@ -1020,7 +1021,7 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, | |||
1020 | { | 1021 | { |
1021 | struct hdac_ext_bus *ebus = get_bus_ctx(substream); | 1022 | struct hdac_ext_bus *ebus = get_bus_ctx(substream); |
1022 | 1023 | ||
1023 | if (!ebus->ppcap) | 1024 | if (!(ebus_to_hbus(ebus))->ppcap) |
1024 | return skl_coupled_trigger(substream, cmd); | 1025 | return skl_coupled_trigger(substream, cmd); |
1025 | 1026 | ||
1026 | return 0; | 1027 | return 0; |
@@ -1138,20 +1139,67 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
1138 | return retval; | 1139 | return retval; |
1139 | } | 1140 | } |
1140 | 1141 | ||
1142 | static int skl_populate_modules(struct skl *skl) | ||
1143 | { | ||
1144 | struct skl_pipeline *p; | ||
1145 | struct skl_pipe_module *m; | ||
1146 | struct snd_soc_dapm_widget *w; | ||
1147 | struct skl_module_cfg *mconfig; | ||
1148 | int ret; | ||
1149 | |||
1150 | list_for_each_entry(p, &skl->ppl_list, node) { | ||
1151 | list_for_each_entry(m, &p->pipe->w_list, node) { | ||
1152 | |||
1153 | w = m->w; | ||
1154 | mconfig = w->priv; | ||
1155 | |||
1156 | ret = snd_skl_get_module_info(skl->skl_sst, mconfig); | ||
1157 | if (ret < 0) { | ||
1158 | dev_err(skl->skl_sst->dev, | ||
1159 | "query module info failed:%d\n", ret); | ||
1160 | goto err; | ||
1161 | } | ||
1162 | } | ||
1163 | } | ||
1164 | err: | ||
1165 | return ret; | ||
1166 | } | ||
1167 | |||
1141 | static int skl_platform_soc_probe(struct snd_soc_platform *platform) | 1168 | static int skl_platform_soc_probe(struct snd_soc_platform *platform) |
1142 | { | 1169 | { |
1143 | struct hdac_ext_bus *ebus = dev_get_drvdata(platform->dev); | 1170 | struct hdac_ext_bus *ebus = dev_get_drvdata(platform->dev); |
1144 | struct skl *skl = ebus_to_skl(ebus); | 1171 | struct skl *skl = ebus_to_skl(ebus); |
1172 | const struct skl_dsp_ops *ops; | ||
1145 | int ret; | 1173 | int ret; |
1146 | 1174 | ||
1147 | if (ebus->ppcap) { | 1175 | pm_runtime_get_sync(platform->dev); |
1176 | if ((ebus_to_hbus(ebus))->ppcap) { | ||
1148 | ret = skl_tplg_init(platform, ebus); | 1177 | ret = skl_tplg_init(platform, ebus); |
1149 | if (ret < 0) { | 1178 | if (ret < 0) { |
1150 | dev_err(platform->dev, "Failed to init topology!\n"); | 1179 | dev_err(platform->dev, "Failed to init topology!\n"); |
1151 | return ret; | 1180 | return ret; |
1152 | } | 1181 | } |
1153 | skl->platform = platform; | 1182 | skl->platform = platform; |
1183 | |||
1184 | /* load the firmwares, since all is set */ | ||
1185 | ops = skl_get_dsp_ops(skl->pci->device); | ||
1186 | if (!ops) | ||
1187 | return -EIO; | ||
1188 | |||
1189 | if (skl->skl_sst->is_first_boot == false) { | ||
1190 | dev_err(platform->dev, "DSP reports first boot done!!!\n"); | ||
1191 | return -EIO; | ||
1192 | } | ||
1193 | |||
1194 | ret = ops->init_fw(platform->dev, skl->skl_sst); | ||
1195 | if (ret < 0) { | ||
1196 | dev_err(platform->dev, "Failed to boot first fw: %d\n", ret); | ||
1197 | return ret; | ||
1198 | } | ||
1199 | skl_populate_modules(skl); | ||
1154 | } | 1200 | } |
1201 | pm_runtime_mark_last_busy(platform->dev); | ||
1202 | pm_runtime_put_autosuspend(platform->dev); | ||
1155 | 1203 | ||
1156 | return 0; | 1204 | return 0; |
1157 | } | 1205 | } |
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index da2329d17f4d..efa2532114ba 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c | |||
@@ -341,14 +341,14 @@ int skl_cldma_prepare(struct sst_dsp *ctx) | |||
341 | ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, | 341 | ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, |
342 | &ctx->cl_dev.dmab_data, ctx->cl_dev.bufsize); | 342 | &ctx->cl_dev.dmab_data, ctx->cl_dev.bufsize); |
343 | if (ret < 0) { | 343 | if (ret < 0) { |
344 | dev_err(ctx->dev, "Alloc buffer for base fw failed: %x", ret); | 344 | dev_err(ctx->dev, "Alloc buffer for base fw failed: %x\n", ret); |
345 | return ret; | 345 | return ret; |
346 | } | 346 | } |
347 | /* Setup Code loader BDL */ | 347 | /* Setup Code loader BDL */ |
348 | ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, | 348 | ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, |
349 | &ctx->cl_dev.dmab_bdl, PAGE_SIZE); | 349 | &ctx->cl_dev.dmab_bdl, PAGE_SIZE); |
350 | if (ret < 0) { | 350 | if (ret < 0) { |
351 | dev_err(ctx->dev, "Alloc buffer for blde failed: %x", ret); | 351 | dev_err(ctx->dev, "Alloc buffer for blde failed: %x\n", ret); |
352 | ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); | 352 | ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); |
353 | return ret; | 353 | return ret; |
354 | } | 354 | } |
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index 0f8629ef79ac..b9e71d051fb1 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <sound/memalloc.h> | 20 | #include <sound/memalloc.h> |
21 | #include "skl-sst-cldma.h" | 21 | #include "skl-sst-cldma.h" |
22 | #include "skl-tplg-interface.h" | 22 | #include "skl-tplg-interface.h" |
23 | #include "skl-topology.h" | ||
23 | 24 | ||
24 | struct sst_dsp; | 25 | struct sst_dsp; |
25 | struct skl_sst; | 26 | struct skl_sst; |
@@ -133,6 +134,8 @@ enum skl_dsp_states { | |||
133 | struct skl_dsp_fw_ops { | 134 | struct skl_dsp_fw_ops { |
134 | int (*load_fw)(struct sst_dsp *ctx); | 135 | int (*load_fw)(struct sst_dsp *ctx); |
135 | /* FW module parser/loader */ | 136 | /* FW module parser/loader */ |
137 | int (*load_library)(struct sst_dsp *ctx, | ||
138 | struct skl_dfw_manifest *minfo); | ||
136 | int (*parse_fw)(struct sst_dsp *ctx); | 139 | int (*parse_fw)(struct sst_dsp *ctx); |
137 | int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id); | 140 | int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id); |
138 | int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id); | 141 | int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id); |
@@ -203,12 +206,21 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, | |||
203 | int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, | 206 | int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, |
204 | const char *fw_name, struct skl_dsp_loader_ops dsp_ops, | 207 | const char *fw_name, struct skl_dsp_loader_ops dsp_ops, |
205 | struct skl_sst **dsp); | 208 | struct skl_sst **dsp); |
209 | int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx); | ||
210 | int bxt_sst_init_fw(struct device *dev, struct skl_sst *ctx); | ||
206 | void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); | 211 | void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); |
207 | void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); | 212 | void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); |
208 | 213 | ||
209 | int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid, | 214 | int snd_skl_get_module_info(struct skl_sst *ctx, |
210 | struct skl_dfw_module *dfw_config); | 215 | struct skl_module_cfg *mconfig); |
211 | int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset); | 216 | int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, |
217 | unsigned int offset, int index); | ||
218 | int skl_get_pvt_id(struct skl_sst *ctx, | ||
219 | struct skl_module_cfg *mconfig); | ||
220 | int skl_put_pvt_id(struct skl_sst *ctx, | ||
221 | struct skl_module_cfg *mconfig); | ||
222 | int skl_get_pvt_instance_id_map(struct skl_sst *ctx, | ||
223 | int module_id, int instance_id); | ||
212 | void skl_freeup_uuid_list(struct skl_sst *ctx); | 224 | void skl_freeup_uuid_list(struct skl_sst *ctx); |
213 | 225 | ||
214 | int skl_dsp_strip_extended_manifest(struct firmware *fw); | 226 | int skl_dsp_strip_extended_manifest(struct firmware *fw); |
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 96f2f6889b18..0bd01e62622c 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c | |||
@@ -114,6 +114,11 @@ | |||
114 | #define IPC_CORE_ID(x) (((x) & IPC_CORE_ID_MASK) \ | 114 | #define IPC_CORE_ID(x) (((x) & IPC_CORE_ID_MASK) \ |
115 | << IPC_CORE_ID_SHIFT) | 115 | << IPC_CORE_ID_SHIFT) |
116 | 116 | ||
117 | #define IPC_DOMAIN_SHIFT 28 | ||
118 | #define IPC_DOMAIN_MASK 0x1 | ||
119 | #define IPC_DOMAIN(x) (((x) & IPC_DOMAIN_MASK) \ | ||
120 | << IPC_DOMAIN_SHIFT) | ||
121 | |||
117 | /* Bind/Unbind message extension register */ | 122 | /* Bind/Unbind message extension register */ |
118 | #define IPC_DST_MOD_ID_SHIFT 0 | 123 | #define IPC_DST_MOD_ID_SHIFT 0 |
119 | #define IPC_DST_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ | 124 | #define IPC_DST_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ |
@@ -190,6 +195,7 @@ enum skl_ipc_glb_type { | |||
190 | IPC_GLB_GET_PPL_CONTEXT_SIZE = 21, | 195 | IPC_GLB_GET_PPL_CONTEXT_SIZE = 21, |
191 | IPC_GLB_SAVE_PPL = 22, | 196 | IPC_GLB_SAVE_PPL = 22, |
192 | IPC_GLB_RESTORE_PPL = 23, | 197 | IPC_GLB_RESTORE_PPL = 23, |
198 | IPC_GLB_LOAD_LIBRARY = 24, | ||
193 | IPC_GLB_NOTIFY = 26, | 199 | IPC_GLB_NOTIFY = 26, |
194 | IPC_GLB_MAX_IPC_MSG_NUMBER = 31 /* Maximum message number */ | 200 | IPC_GLB_MAX_IPC_MSG_NUMBER = 31 /* Maximum message number */ |
195 | }; | 201 | }; |
@@ -338,7 +344,7 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc, | |||
338 | break; | 344 | break; |
339 | 345 | ||
340 | default: | 346 | default: |
341 | dev_err(ipc->dev, "ipc: Unhandled error msg=%x", | 347 | dev_err(ipc->dev, "ipc: Unhandled error msg=%x\n", |
342 | header.primary); | 348 | header.primary); |
343 | break; | 349 | break; |
344 | } | 350 | } |
@@ -379,13 +385,13 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, | |||
379 | break; | 385 | break; |
380 | 386 | ||
381 | default: | 387 | default: |
382 | dev_err(ipc->dev, "Unknown ipc reply: 0x%x", reply); | 388 | dev_err(ipc->dev, "Unknown ipc reply: 0x%x\n", reply); |
383 | msg->errno = -EINVAL; | 389 | msg->errno = -EINVAL; |
384 | break; | 390 | break; |
385 | } | 391 | } |
386 | 392 | ||
387 | if (reply != IPC_GLB_REPLY_SUCCESS) { | 393 | if (reply != IPC_GLB_REPLY_SUCCESS) { |
388 | dev_err(ipc->dev, "ipc FW reply: reply=%d", reply); | 394 | dev_err(ipc->dev, "ipc FW reply: reply=%d\n", reply); |
389 | dev_err(ipc->dev, "FW Error Code: %u\n", | 395 | dev_err(ipc->dev, "FW Error Code: %u\n", |
390 | ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); | 396 | ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); |
391 | } | 397 | } |
@@ -434,9 +440,9 @@ irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) | |||
434 | hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE); | 440 | hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE); |
435 | header.primary = hipct; | 441 | header.primary = hipct; |
436 | header.extension = hipcte; | 442 | header.extension = hipcte; |
437 | dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x", | 443 | dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x\n", |
438 | header.primary); | 444 | header.primary); |
439 | dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x", | 445 | dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x\n", |
440 | header.extension); | 446 | header.extension); |
441 | 447 | ||
442 | if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { | 448 | if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { |
@@ -704,6 +710,7 @@ int skl_ipc_init_instance(struct sst_generic_ipc *ipc, | |||
704 | header.extension = IPC_CORE_ID(msg->core_id); | 710 | header.extension = IPC_CORE_ID(msg->core_id); |
705 | header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id); | 711 | header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id); |
706 | header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size); | 712 | header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size); |
713 | header.extension |= IPC_DOMAIN(msg->domain); | ||
707 | 714 | ||
708 | dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, | 715 | dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, |
709 | header.primary, header.extension); | 716 | header.primary, header.extension); |
@@ -742,7 +749,7 @@ int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, | |||
742 | header.extension); | 749 | header.extension); |
743 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); | 750 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); |
744 | if (ret < 0) { | 751 | if (ret < 0) { |
745 | dev_err(ipc->dev, "ipc: bind/unbind faileden"); | 752 | dev_err(ipc->dev, "ipc: bind/unbind failed\n"); |
746 | return ret; | 753 | return ret; |
747 | } | 754 | } |
748 | 755 | ||
@@ -902,3 +909,25 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, | |||
902 | return ret; | 909 | return ret; |
903 | } | 910 | } |
904 | EXPORT_SYMBOL_GPL(skl_ipc_get_large_config); | 911 | EXPORT_SYMBOL_GPL(skl_ipc_get_large_config); |
912 | |||
913 | int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, | ||
914 | u8 dma_id, u8 table_id) | ||
915 | { | ||
916 | struct skl_ipc_header header = {0}; | ||
917 | u64 *ipc_header = (u64 *)(&header); | ||
918 | int ret = 0; | ||
919 | |||
920 | header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); | ||
921 | header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); | ||
922 | header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_LIBRARY); | ||
923 | header.primary |= IPC_MOD_INSTANCE_ID(table_id); | ||
924 | header.primary |= IPC_MOD_ID(dma_id); | ||
925 | |||
926 | ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); | ||
927 | |||
928 | if (ret < 0) | ||
929 | dev_err(ipc->dev, "ipc: load lib failed\n"); | ||
930 | |||
931 | return ret; | ||
932 | } | ||
933 | EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library); | ||
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 2e3d4e80ef97..0334ed4af031 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h | |||
@@ -66,7 +66,7 @@ struct skl_sst { | |||
66 | 66 | ||
67 | /* callback for miscbdge */ | 67 | /* callback for miscbdge */ |
68 | void (*enable_miscbdcge)(struct device *dev, bool enable); | 68 | void (*enable_miscbdcge)(struct device *dev, bool enable); |
69 | /*Is CGCTL.MISCBDCGE disabled*/ | 69 | /* Is CGCTL.MISCBDCGE disabled */ |
70 | bool miscbdcg_disabled; | 70 | bool miscbdcg_disabled; |
71 | 71 | ||
72 | /* Populate module information */ | 72 | /* Populate module information */ |
@@ -75,8 +75,14 @@ struct skl_sst { | |||
75 | /* Is firmware loaded */ | 75 | /* Is firmware loaded */ |
76 | bool fw_loaded; | 76 | bool fw_loaded; |
77 | 77 | ||
78 | /* first boot ? */ | ||
79 | bool is_first_boot; | ||
80 | |||
78 | /* multi-core */ | 81 | /* multi-core */ |
79 | struct skl_dsp_cores cores; | 82 | struct skl_dsp_cores cores; |
83 | |||
84 | /* tplg manifest */ | ||
85 | struct skl_dfw_manifest manifest; | ||
80 | }; | 86 | }; |
81 | 87 | ||
82 | struct skl_ipc_init_instance_msg { | 88 | struct skl_ipc_init_instance_msg { |
@@ -85,6 +91,7 @@ struct skl_ipc_init_instance_msg { | |||
85 | u16 param_data_size; | 91 | u16 param_data_size; |
86 | u8 ppl_instance_id; | 92 | u8 ppl_instance_id; |
87 | u8 core_id; | 93 | u8 core_id; |
94 | u8 domain; | ||
88 | }; | 95 | }; |
89 | 96 | ||
90 | struct skl_ipc_bind_unbind_msg { | 97 | struct skl_ipc_bind_unbind_msg { |
@@ -145,6 +152,9 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, | |||
145 | int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, | 152 | int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, |
146 | struct skl_ipc_large_config_msg *msg, u32 *param); | 153 | struct skl_ipc_large_config_msg *msg, u32 *param); |
147 | 154 | ||
155 | int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, | ||
156 | u8 dma_id, u8 table_id); | ||
157 | |||
148 | void skl_ipc_int_enable(struct sst_dsp *dsp); | 158 | void skl_ipc_int_enable(struct sst_dsp *dsp); |
149 | void skl_ipc_op_int_enable(struct sst_dsp *ctx); | 159 | void skl_ipc_op_int_enable(struct sst_dsp *ctx); |
150 | void skl_ipc_op_int_disable(struct sst_dsp *ctx); | 160 | void skl_ipc_op_int_disable(struct sst_dsp *ctx); |
diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c index ddcb52a51854..8dc03039b311 100644 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ b/sound/soc/intel/skylake/skl-sst-utils.c | |||
@@ -28,11 +28,6 @@ | |||
28 | /* FW Extended Manifest Header id = $AE1 */ | 28 | /* FW Extended Manifest Header id = $AE1 */ |
29 | #define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124 | 29 | #define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124 |
30 | 30 | ||
31 | struct skl_dfw_module_mod { | ||
32 | char name[100]; | ||
33 | struct skl_dfw_module skl_dfw_mod; | ||
34 | }; | ||
35 | |||
36 | struct UUID { | 31 | struct UUID { |
37 | u8 id[16]; | 32 | u8 id[16]; |
38 | }; | 33 | }; |
@@ -99,10 +94,15 @@ struct adsp_fw_hdr { | |||
99 | u32 load_offset; | 94 | u32 load_offset; |
100 | } __packed; | 95 | } __packed; |
101 | 96 | ||
97 | #define MAX_INSTANCE_BUFF 2 | ||
98 | |||
102 | struct uuid_module { | 99 | struct uuid_module { |
103 | uuid_le uuid; | 100 | uuid_le uuid; |
104 | int id; | 101 | int id; |
105 | int is_loadable; | 102 | int is_loadable; |
103 | int max_instance; | ||
104 | u64 pvt_id[MAX_INSTANCE_BUFF]; | ||
105 | int *instance_id; | ||
106 | 106 | ||
107 | struct list_head list; | 107 | struct list_head list; |
108 | }; | 108 | }; |
@@ -115,13 +115,13 @@ struct skl_ext_manifest_hdr { | |||
115 | u32 entries; | 115 | u32 entries; |
116 | }; | 116 | }; |
117 | 117 | ||
118 | int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid, | 118 | int snd_skl_get_module_info(struct skl_sst *ctx, |
119 | struct skl_dfw_module *dfw_config) | 119 | struct skl_module_cfg *mconfig) |
120 | { | 120 | { |
121 | struct uuid_module *module; | 121 | struct uuid_module *module; |
122 | uuid_le *uuid_mod; | 122 | uuid_le *uuid_mod; |
123 | 123 | ||
124 | uuid_mod = (uuid_le *)uuid; | 124 | uuid_mod = (uuid_le *)mconfig->guid; |
125 | 125 | ||
126 | if (list_empty(&ctx->uuid_list)) { | 126 | if (list_empty(&ctx->uuid_list)) { |
127 | dev_err(ctx->dev, "Module list is empty\n"); | 127 | dev_err(ctx->dev, "Module list is empty\n"); |
@@ -130,8 +130,8 @@ int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid, | |||
130 | 130 | ||
131 | list_for_each_entry(module, &ctx->uuid_list, list) { | 131 | list_for_each_entry(module, &ctx->uuid_list, list) { |
132 | if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { | 132 | if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { |
133 | dfw_config->module_id = module->id; | 133 | mconfig->id.module_id = module->id; |
134 | dfw_config->is_loadable = module->is_loadable; | 134 | mconfig->is_loadable = module->is_loadable; |
135 | 135 | ||
136 | return 0; | 136 | return 0; |
137 | } | 137 | } |
@@ -141,15 +141,154 @@ int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid, | |||
141 | } | 141 | } |
142 | EXPORT_SYMBOL_GPL(snd_skl_get_module_info); | 142 | EXPORT_SYMBOL_GPL(snd_skl_get_module_info); |
143 | 143 | ||
144 | static int skl_get_pvtid_map(struct uuid_module *module, int instance_id) | ||
145 | { | ||
146 | int pvt_id; | ||
147 | |||
148 | for (pvt_id = 0; pvt_id < module->max_instance; pvt_id++) { | ||
149 | if (module->instance_id[pvt_id] == instance_id) | ||
150 | return pvt_id; | ||
151 | } | ||
152 | return -EINVAL; | ||
153 | } | ||
154 | |||
155 | int skl_get_pvt_instance_id_map(struct skl_sst *ctx, | ||
156 | int module_id, int instance_id) | ||
157 | { | ||
158 | struct uuid_module *module; | ||
159 | |||
160 | list_for_each_entry(module, &ctx->uuid_list, list) { | ||
161 | if (module->id == module_id) | ||
162 | return skl_get_pvtid_map(module, instance_id); | ||
163 | } | ||
164 | |||
165 | return -EINVAL; | ||
166 | } | ||
167 | EXPORT_SYMBOL_GPL(skl_get_pvt_instance_id_map); | ||
168 | |||
169 | static inline int skl_getid_32(struct uuid_module *module, u64 *val, | ||
170 | int word1_mask, int word2_mask) | ||
171 | { | ||
172 | int index, max_inst, pvt_id; | ||
173 | u32 mask_val; | ||
174 | |||
175 | max_inst = module->max_instance; | ||
176 | mask_val = (u32)(*val >> word1_mask); | ||
177 | |||
178 | if (mask_val != 0xffffffff) { | ||
179 | index = ffz(mask_val); | ||
180 | pvt_id = index + word1_mask + word2_mask; | ||
181 | if (pvt_id <= (max_inst - 1)) { | ||
182 | *val |= 1 << (index + word1_mask); | ||
183 | return pvt_id; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | return -EINVAL; | ||
188 | } | ||
189 | |||
190 | static inline int skl_pvtid_128(struct uuid_module *module) | ||
191 | { | ||
192 | int j, i, word1_mask, word2_mask = 0, pvt_id; | ||
193 | |||
194 | for (j = 0; j < MAX_INSTANCE_BUFF; j++) { | ||
195 | word1_mask = 0; | ||
196 | |||
197 | for (i = 0; i < 2; i++) { | ||
198 | pvt_id = skl_getid_32(module, &module->pvt_id[j], | ||
199 | word1_mask, word2_mask); | ||
200 | if (pvt_id >= 0) | ||
201 | return pvt_id; | ||
202 | |||
203 | word1_mask += 32; | ||
204 | if ((word1_mask + word2_mask) >= module->max_instance) | ||
205 | return -EINVAL; | ||
206 | } | ||
207 | |||
208 | word2_mask += 64; | ||
209 | if (word2_mask >= module->max_instance) | ||
210 | return -EINVAL; | ||
211 | } | ||
212 | |||
213 | return -EINVAL; | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * skl_get_pvt_id: generate a private id for use as module id | ||
218 | * | ||
219 | * @ctx: driver context | ||
220 | * @mconfig: module configuration data | ||
221 | * | ||
222 | * This generates a 128 bit private unique id for a module TYPE so that | ||
223 | * module instance is unique | ||
224 | */ | ||
225 | int skl_get_pvt_id(struct skl_sst *ctx, struct skl_module_cfg *mconfig) | ||
226 | { | ||
227 | struct uuid_module *module; | ||
228 | uuid_le *uuid_mod; | ||
229 | int pvt_id; | ||
230 | |||
231 | uuid_mod = (uuid_le *)mconfig->guid; | ||
232 | |||
233 | list_for_each_entry(module, &ctx->uuid_list, list) { | ||
234 | if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { | ||
235 | |||
236 | pvt_id = skl_pvtid_128(module); | ||
237 | if (pvt_id >= 0) { | ||
238 | module->instance_id[pvt_id] = | ||
239 | mconfig->id.instance_id; | ||
240 | return pvt_id; | ||
241 | } | ||
242 | } | ||
243 | } | ||
244 | |||
245 | return -EINVAL; | ||
246 | } | ||
247 | EXPORT_SYMBOL_GPL(skl_get_pvt_id); | ||
248 | |||
249 | /** | ||
250 | * skl_put_pvt_id: free up the private id allocated | ||
251 | * | ||
252 | * @ctx: driver context | ||
253 | * @mconfig: module configuration data | ||
254 | * | ||
255 | * This frees a 128 bit private unique id previously generated | ||
256 | */ | ||
257 | int skl_put_pvt_id(struct skl_sst *ctx, struct skl_module_cfg *mconfig) | ||
258 | { | ||
259 | int i; | ||
260 | uuid_le *uuid_mod; | ||
261 | struct uuid_module *module; | ||
262 | |||
263 | uuid_mod = (uuid_le *)mconfig->guid; | ||
264 | list_for_each_entry(module, &ctx->uuid_list, list) { | ||
265 | if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { | ||
266 | |||
267 | if (mconfig->id.pvt_id != 0) | ||
268 | i = (mconfig->id.pvt_id) / 64; | ||
269 | else | ||
270 | i = 0; | ||
271 | |||
272 | module->pvt_id[i] &= ~(1 << (mconfig->id.pvt_id)); | ||
273 | mconfig->id.pvt_id = -1; | ||
274 | return 0; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | return -EINVAL; | ||
279 | } | ||
280 | EXPORT_SYMBOL_GPL(skl_put_pvt_id); | ||
281 | |||
144 | /* | 282 | /* |
145 | * Parse the firmware binary to get the UUID, module id | 283 | * Parse the firmware binary to get the UUID, module id |
146 | * and loadable flags | 284 | * and loadable flags |
147 | */ | 285 | */ |
148 | int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset) | 286 | int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, |
287 | unsigned int offset, int index) | ||
149 | { | 288 | { |
150 | struct adsp_fw_hdr *adsp_hdr; | 289 | struct adsp_fw_hdr *adsp_hdr; |
151 | struct adsp_module_entry *mod_entry; | 290 | struct adsp_module_entry *mod_entry; |
152 | int i, num_entry; | 291 | int i, num_entry, size; |
153 | uuid_le *uuid_bin; | 292 | uuid_le *uuid_bin; |
154 | const char *buf; | 293 | const char *buf; |
155 | struct skl_sst *skl = ctx->thread_context; | 294 | struct skl_sst *skl = ctx->thread_context; |
@@ -158,8 +297,8 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset) | |||
158 | unsigned int safe_file; | 297 | unsigned int safe_file; |
159 | 298 | ||
160 | /* Get the FW pointer to derive ADSP header */ | 299 | /* Get the FW pointer to derive ADSP header */ |
161 | stripped_fw.data = ctx->fw->data; | 300 | stripped_fw.data = fw->data; |
162 | stripped_fw.size = ctx->fw->size; | 301 | stripped_fw.size = fw->size; |
163 | 302 | ||
164 | skl_dsp_strip_extended_manifest(&stripped_fw); | 303 | skl_dsp_strip_extended_manifest(&stripped_fw); |
165 | 304 | ||
@@ -210,8 +349,15 @@ int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset) | |||
210 | uuid_bin = (uuid_le *)mod_entry->uuid.id; | 349 | uuid_bin = (uuid_le *)mod_entry->uuid.id; |
211 | memcpy(&module->uuid, uuid_bin, sizeof(module->uuid)); | 350 | memcpy(&module->uuid, uuid_bin, sizeof(module->uuid)); |
212 | 351 | ||
213 | module->id = i; | 352 | module->id = (i | (index << 12)); |
214 | module->is_loadable = mod_entry->type.load_type; | 353 | module->is_loadable = mod_entry->type.load_type; |
354 | module->max_instance = mod_entry->instance_max_count; | ||
355 | size = sizeof(int) * mod_entry->instance_max_count; | ||
356 | module->instance_id = devm_kzalloc(ctx->dev, size, GFP_KERNEL); | ||
357 | if (!module->instance_id) { | ||
358 | kfree(module); | ||
359 | return -ENOMEM; | ||
360 | } | ||
215 | 361 | ||
216 | list_add_tail(&module->list, &skl->uuid_list); | 362 | list_add_tail(&module->list, &skl->uuid_list); |
217 | 363 | ||
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 588f899ceb65..8fc3178bc79c 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c | |||
@@ -88,13 +88,15 @@ static int skl_load_base_firmware(struct sst_dsp *ctx) | |||
88 | } | 88 | } |
89 | } | 89 | } |
90 | 90 | ||
91 | ret = snd_skl_parse_uuids(ctx, SKL_ADSP_FW_BIN_HDR_OFFSET); | 91 | /* prase uuids on first boot */ |
92 | if (ret < 0) { | 92 | if (skl->is_first_boot) { |
93 | dev_err(ctx->dev, | 93 | ret = snd_skl_parse_uuids(ctx, ctx->fw, SKL_ADSP_FW_BIN_HDR_OFFSET, 0); |
94 | "UUID parsing err: %d\n", ret); | 94 | if (ret < 0) { |
95 | release_firmware(ctx->fw); | 95 | dev_err(ctx->dev, "UUID parsing err: %d\n", ret); |
96 | skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); | 96 | release_firmware(ctx->fw); |
97 | return ret; | 97 | skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); |
98 | return ret; | ||
99 | } | ||
98 | } | 100 | } |
99 | 101 | ||
100 | /* check for extended manifest */ | 102 | /* check for extended manifest */ |
@@ -105,13 +107,13 @@ static int skl_load_base_firmware(struct sst_dsp *ctx) | |||
105 | 107 | ||
106 | ret = skl_dsp_boot(ctx); | 108 | ret = skl_dsp_boot(ctx); |
107 | if (ret < 0) { | 109 | if (ret < 0) { |
108 | dev_err(ctx->dev, "Boot dsp core failed ret: %d", ret); | 110 | dev_err(ctx->dev, "Boot dsp core failed ret: %d\n", ret); |
109 | goto skl_load_base_firmware_failed; | 111 | goto skl_load_base_firmware_failed; |
110 | } | 112 | } |
111 | 113 | ||
112 | ret = skl_cldma_prepare(ctx); | 114 | ret = skl_cldma_prepare(ctx); |
113 | if (ret < 0) { | 115 | if (ret < 0) { |
114 | dev_err(ctx->dev, "CL dma prepare failed : %d", ret); | 116 | dev_err(ctx->dev, "CL dma prepare failed : %d\n", ret); |
115 | goto skl_load_base_firmware_failed; | 117 | goto skl_load_base_firmware_failed; |
116 | } | 118 | } |
117 | 119 | ||
@@ -484,25 +486,32 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, | |||
484 | return ret; | 486 | return ret; |
485 | 487 | ||
486 | skl->cores.count = 2; | 488 | skl->cores.count = 2; |
489 | skl->is_first_boot = true; | ||
490 | |||
491 | if (dsp) | ||
492 | *dsp = skl; | ||
493 | |||
494 | return ret; | ||
495 | } | ||
496 | EXPORT_SYMBOL_GPL(skl_sst_dsp_init); | ||
497 | |||
498 | int skl_sst_init_fw(struct device *dev, struct skl_sst *ctx) | ||
499 | { | ||
500 | int ret; | ||
501 | struct sst_dsp *sst = ctx->dsp; | ||
487 | 502 | ||
488 | ret = sst->fw_ops.load_fw(sst); | 503 | ret = sst->fw_ops.load_fw(sst); |
489 | if (ret < 0) { | 504 | if (ret < 0) { |
490 | dev_err(dev, "Load base fw failed : %d", ret); | 505 | dev_err(dev, "Load base fw failed : %d\n", ret); |
491 | goto cleanup; | 506 | return ret; |
492 | } | 507 | } |
493 | 508 | ||
494 | skl_dsp_init_core_state(sst); | 509 | skl_dsp_init_core_state(sst); |
510 | ctx->is_first_boot = false; | ||
495 | 511 | ||
496 | if (dsp) | 512 | return 0; |
497 | *dsp = skl; | ||
498 | |||
499 | return ret; | ||
500 | |||
501 | cleanup: | ||
502 | skl_sst_dsp_cleanup(dev, skl); | ||
503 | return ret; | ||
504 | } | 513 | } |
505 | EXPORT_SYMBOL_GPL(skl_sst_dsp_init); | 514 | EXPORT_SYMBOL_GPL(skl_sst_init_fw); |
506 | 515 | ||
507 | void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) | 516 | void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) |
508 | { | 517 | { |
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index cc0150fc2601..b5b1934d8550 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/firmware.h> | 21 | #include <linux/firmware.h> |
22 | #include <sound/soc.h> | 22 | #include <sound/soc.h> |
23 | #include <sound/soc-topology.h> | 23 | #include <sound/soc-topology.h> |
24 | #include <uapi/sound/snd_sst_tokens.h> | ||
24 | #include "skl-sst-dsp.h" | 25 | #include "skl-sst-dsp.h" |
25 | #include "skl-sst-ipc.h" | 26 | #include "skl-sst-ipc.h" |
26 | #include "skl-topology.h" | 27 | #include "skl-topology.h" |
@@ -32,6 +33,8 @@ | |||
32 | #define SKL_CH_FIXUP_MASK (1 << 0) | 33 | #define SKL_CH_FIXUP_MASK (1 << 0) |
33 | #define SKL_RATE_FIXUP_MASK (1 << 1) | 34 | #define SKL_RATE_FIXUP_MASK (1 << 1) |
34 | #define SKL_FMT_FIXUP_MASK (1 << 2) | 35 | #define SKL_FMT_FIXUP_MASK (1 << 2) |
36 | #define SKL_IN_DIR_BIT_MASK BIT(0) | ||
37 | #define SKL_PIN_COUNT_MASK GENMASK(7, 4) | ||
35 | 38 | ||
36 | /* | 39 | /* |
37 | * SKL DSP driver modelling uses only few DAPM widgets so for rest we will | 40 | * SKL DSP driver modelling uses only few DAPM widgets so for rest we will |
@@ -473,6 +476,14 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) | |||
473 | w = w_module->w; | 476 | w = w_module->w; |
474 | mconfig = w->priv; | 477 | mconfig = w->priv; |
475 | 478 | ||
479 | /* check if module ids are populated */ | ||
480 | if (mconfig->id.module_id < 0) { | ||
481 | dev_err(skl->skl_sst->dev, | ||
482 | "module %pUL id not populated\n", | ||
483 | (uuid_le *)mconfig->guid); | ||
484 | return -EIO; | ||
485 | } | ||
486 | |||
476 | /* check resource available */ | 487 | /* check resource available */ |
477 | if (!skl_is_pipe_mcps_avail(skl, mconfig)) | 488 | if (!skl_is_pipe_mcps_avail(skl, mconfig)) |
478 | return -ENOMEM; | 489 | return -ENOMEM; |
@@ -494,12 +505,15 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) | |||
494 | * FE/BE params | 505 | * FE/BE params |
495 | */ | 506 | */ |
496 | skl_tplg_update_module_params(w, ctx); | 507 | skl_tplg_update_module_params(w, ctx); |
497 | 508 | mconfig->id.pvt_id = skl_get_pvt_id(ctx, mconfig); | |
509 | if (mconfig->id.pvt_id < 0) | ||
510 | return ret; | ||
498 | skl_tplg_set_module_init_data(w); | 511 | skl_tplg_set_module_init_data(w); |
499 | ret = skl_init_module(ctx, mconfig); | 512 | ret = skl_init_module(ctx, mconfig); |
500 | if (ret < 0) | 513 | if (ret < 0) { |
514 | skl_put_pvt_id(ctx, mconfig); | ||
501 | return ret; | 515 | return ret; |
502 | 516 | } | |
503 | skl_tplg_alloc_pipe_mcps(skl, mconfig); | 517 | skl_tplg_alloc_pipe_mcps(skl, mconfig); |
504 | ret = skl_tplg_set_module_params(w, ctx); | 518 | ret = skl_tplg_set_module_params(w, ctx); |
505 | if (ret < 0) | 519 | if (ret < 0) |
@@ -512,6 +526,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) | |||
512 | static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, | 526 | static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, |
513 | struct skl_pipe *pipe) | 527 | struct skl_pipe *pipe) |
514 | { | 528 | { |
529 | int ret; | ||
515 | struct skl_pipe_module *w_module = NULL; | 530 | struct skl_pipe_module *w_module = NULL; |
516 | struct skl_module_cfg *mconfig = NULL; | 531 | struct skl_module_cfg *mconfig = NULL; |
517 | 532 | ||
@@ -519,9 +534,13 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, | |||
519 | mconfig = w_module->w->priv; | 534 | mconfig = w_module->w->priv; |
520 | 535 | ||
521 | if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod && | 536 | if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod && |
522 | mconfig->m_state > SKL_MODULE_UNINIT) | 537 | mconfig->m_state > SKL_MODULE_UNINIT) { |
523 | return ctx->dsp->fw_ops.unload_mod(ctx->dsp, | 538 | ret = ctx->dsp->fw_ops.unload_mod(ctx->dsp, |
524 | mconfig->id.module_id); | 539 | mconfig->id.module_id); |
540 | if (ret < 0) | ||
541 | return -EIO; | ||
542 | } | ||
543 | skl_put_pvt_id(ctx, mconfig); | ||
525 | } | 544 | } |
526 | 545 | ||
527 | /* no modules to unload in this path, so return */ | 546 | /* no modules to unload in this path, so return */ |
@@ -588,6 +607,26 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, | |||
588 | return 0; | 607 | return 0; |
589 | } | 608 | } |
590 | 609 | ||
610 | static int skl_fill_sink_instance_id(struct skl_sst *ctx, | ||
611 | struct skl_algo_data *alg_data) | ||
612 | { | ||
613 | struct skl_kpb_params *params = (struct skl_kpb_params *)alg_data->params; | ||
614 | struct skl_mod_inst_map *inst; | ||
615 | int i, pvt_id; | ||
616 | |||
617 | inst = params->map; | ||
618 | |||
619 | for (i = 0; i < params->num_modules; i++) { | ||
620 | pvt_id = skl_get_pvt_instance_id_map(ctx, | ||
621 | inst->mod_id, inst->inst_id); | ||
622 | if (pvt_id < 0) | ||
623 | return -EINVAL; | ||
624 | inst->inst_id = pvt_id; | ||
625 | inst++; | ||
626 | } | ||
627 | return 0; | ||
628 | } | ||
629 | |||
591 | /* | 630 | /* |
592 | * Some modules require params to be set after the module is bound to | 631 | * Some modules require params to be set after the module is bound to |
593 | * all pins connected. | 632 | * all pins connected. |
@@ -636,6 +675,8 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, | |||
636 | bc = (struct skl_algo_data *)sb->dobj.private; | 675 | bc = (struct skl_algo_data *)sb->dobj.private; |
637 | 676 | ||
638 | if (bc->set_params == SKL_PARAM_BIND) { | 677 | if (bc->set_params == SKL_PARAM_BIND) { |
678 | if (mconfig->m_type == SKL_MODULE_TYPE_KPB) | ||
679 | skl_fill_sink_instance_id(ctx, bc); | ||
639 | ret = skl_set_module_params(ctx, | 680 | ret = skl_set_module_params(ctx, |
640 | (u32 *)bc->params, bc->max, | 681 | (u32 *)bc->params, bc->max, |
641 | bc->param_id, mconfig); | 682 | bc->param_id, mconfig); |
@@ -1460,85 +1501,570 @@ static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = { | |||
1460 | skl_tplg_tlv_control_set}, | 1501 | skl_tplg_tlv_control_set}, |
1461 | }; | 1502 | }; |
1462 | 1503 | ||
1463 | /* | 1504 | static int skl_tplg_fill_pipe_tkn(struct device *dev, |
1464 | * The topology binary passes the pin info for a module so initialize the pin | 1505 | struct skl_pipe *pipe, u32 tkn, |
1465 | * info passed into module instance | 1506 | u32 tkn_val) |
1466 | */ | ||
1467 | static void skl_fill_module_pin_info(struct skl_dfw_module_pin *dfw_pin, | ||
1468 | struct skl_module_pin *m_pin, | ||
1469 | bool is_dynamic, int max_pin) | ||
1470 | { | 1507 | { |
1471 | int i; | ||
1472 | 1508 | ||
1473 | for (i = 0; i < max_pin; i++) { | 1509 | switch (tkn) { |
1474 | m_pin[i].id.module_id = dfw_pin[i].module_id; | 1510 | case SKL_TKN_U32_PIPE_CONN_TYPE: |
1475 | m_pin[i].id.instance_id = dfw_pin[i].instance_id; | 1511 | pipe->conn_type = tkn_val; |
1476 | m_pin[i].in_use = false; | 1512 | break; |
1477 | m_pin[i].is_dynamic = is_dynamic; | 1513 | |
1478 | m_pin[i].pin_state = SKL_PIN_UNBIND; | 1514 | case SKL_TKN_U32_PIPE_PRIORITY: |
1515 | pipe->pipe_priority = tkn_val; | ||
1516 | break; | ||
1517 | |||
1518 | case SKL_TKN_U32_PIPE_MEM_PGS: | ||
1519 | pipe->memory_pages = tkn_val; | ||
1520 | break; | ||
1521 | |||
1522 | default: | ||
1523 | dev_err(dev, "Token not handled %d\n", tkn); | ||
1524 | return -EINVAL; | ||
1479 | } | 1525 | } |
1526 | |||
1527 | return 0; | ||
1480 | } | 1528 | } |
1481 | 1529 | ||
1482 | /* | 1530 | /* |
1483 | * Add pipeline from topology binary into driver pipeline list | 1531 | * Add pipeline by parsing the relevant tokens |
1484 | * | 1532 | * Return an existing pipe if the pipe already exists. |
1485 | * If already added we return that instance | ||
1486 | * Otherwise we create a new instance and add into driver list | ||
1487 | */ | 1533 | */ |
1488 | static struct skl_pipe *skl_tplg_add_pipe(struct device *dev, | 1534 | static int skl_tplg_add_pipe(struct device *dev, |
1489 | struct skl *skl, struct skl_dfw_pipe *dfw_pipe) | 1535 | struct skl_module_cfg *mconfig, struct skl *skl, |
1536 | struct snd_soc_tplg_vendor_value_elem *tkn_elem) | ||
1490 | { | 1537 | { |
1491 | struct skl_pipeline *ppl; | 1538 | struct skl_pipeline *ppl; |
1492 | struct skl_pipe *pipe; | 1539 | struct skl_pipe *pipe; |
1493 | struct skl_pipe_params *params; | 1540 | struct skl_pipe_params *params; |
1494 | 1541 | ||
1495 | list_for_each_entry(ppl, &skl->ppl_list, node) { | 1542 | list_for_each_entry(ppl, &skl->ppl_list, node) { |
1496 | if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) | 1543 | if (ppl->pipe->ppl_id == tkn_elem->value) { |
1497 | return ppl->pipe; | 1544 | mconfig->pipe = ppl->pipe; |
1545 | return EEXIST; | ||
1546 | } | ||
1498 | } | 1547 | } |
1499 | 1548 | ||
1500 | ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); | 1549 | ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); |
1501 | if (!ppl) | 1550 | if (!ppl) |
1502 | return NULL; | 1551 | return -ENOMEM; |
1503 | 1552 | ||
1504 | pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); | 1553 | pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); |
1505 | if (!pipe) | 1554 | if (!pipe) |
1506 | return NULL; | 1555 | return -ENOMEM; |
1507 | 1556 | ||
1508 | params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); | 1557 | params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); |
1509 | if (!params) | 1558 | if (!params) |
1510 | return NULL; | 1559 | return -ENOMEM; |
1511 | 1560 | ||
1512 | pipe->ppl_id = dfw_pipe->pipe_id; | ||
1513 | pipe->memory_pages = dfw_pipe->memory_pages; | ||
1514 | pipe->pipe_priority = dfw_pipe->pipe_priority; | ||
1515 | pipe->conn_type = dfw_pipe->conn_type; | ||
1516 | pipe->state = SKL_PIPE_INVALID; | ||
1517 | pipe->p_params = params; | 1561 | pipe->p_params = params; |
1562 | pipe->ppl_id = tkn_elem->value; | ||
1518 | INIT_LIST_HEAD(&pipe->w_list); | 1563 | INIT_LIST_HEAD(&pipe->w_list); |
1519 | 1564 | ||
1520 | ppl->pipe = pipe; | 1565 | ppl->pipe = pipe; |
1521 | list_add(&ppl->node, &skl->ppl_list); | 1566 | list_add(&ppl->node, &skl->ppl_list); |
1522 | 1567 | ||
1523 | return ppl->pipe; | 1568 | mconfig->pipe = pipe; |
1569 | mconfig->pipe->state = SKL_PIPE_INVALID; | ||
1570 | |||
1571 | return 0; | ||
1572 | } | ||
1573 | |||
1574 | static int skl_tplg_fill_pin(struct device *dev, u32 tkn, | ||
1575 | struct skl_module_pin *m_pin, | ||
1576 | int pin_index, u32 value) | ||
1577 | { | ||
1578 | switch (tkn) { | ||
1579 | case SKL_TKN_U32_PIN_MOD_ID: | ||
1580 | m_pin[pin_index].id.module_id = value; | ||
1581 | break; | ||
1582 | |||
1583 | case SKL_TKN_U32_PIN_INST_ID: | ||
1584 | m_pin[pin_index].id.instance_id = value; | ||
1585 | break; | ||
1586 | |||
1587 | default: | ||
1588 | dev_err(dev, "%d Not a pin token\n", value); | ||
1589 | return -EINVAL; | ||
1590 | } | ||
1591 | |||
1592 | return 0; | ||
1593 | } | ||
1594 | |||
1595 | /* | ||
1596 | * Parse for pin config specific tokens to fill up the | ||
1597 | * module private data | ||
1598 | */ | ||
1599 | static int skl_tplg_fill_pins_info(struct device *dev, | ||
1600 | struct skl_module_cfg *mconfig, | ||
1601 | struct snd_soc_tplg_vendor_value_elem *tkn_elem, | ||
1602 | int dir, int pin_count) | ||
1603 | { | ||
1604 | int ret; | ||
1605 | struct skl_module_pin *m_pin; | ||
1606 | |||
1607 | switch (dir) { | ||
1608 | case SKL_DIR_IN: | ||
1609 | m_pin = mconfig->m_in_pin; | ||
1610 | break; | ||
1611 | |||
1612 | case SKL_DIR_OUT: | ||
1613 | m_pin = mconfig->m_out_pin; | ||
1614 | break; | ||
1615 | |||
1616 | default: | ||
1617 | dev_err(dev, "Invalid direction value\n"); | ||
1618 | return -EINVAL; | ||
1619 | } | ||
1620 | |||
1621 | ret = skl_tplg_fill_pin(dev, tkn_elem->token, | ||
1622 | m_pin, pin_count, tkn_elem->value); | ||
1623 | |||
1624 | if (ret < 0) | ||
1625 | return ret; | ||
1626 | |||
1627 | m_pin[pin_count].in_use = false; | ||
1628 | m_pin[pin_count].pin_state = SKL_PIN_UNBIND; | ||
1629 | |||
1630 | return 0; | ||
1631 | } | ||
1632 | |||
1633 | /* | ||
1634 | * Fill up input/output module config format based | ||
1635 | * on the direction | ||
1636 | */ | ||
1637 | static int skl_tplg_fill_fmt(struct device *dev, | ||
1638 | struct skl_module_cfg *mconfig, u32 tkn, | ||
1639 | u32 value, u32 dir, u32 pin_count) | ||
1640 | { | ||
1641 | struct skl_module_fmt *dst_fmt; | ||
1642 | |||
1643 | switch (dir) { | ||
1644 | case SKL_DIR_IN: | ||
1645 | dst_fmt = mconfig->in_fmt; | ||
1646 | dst_fmt += pin_count; | ||
1647 | break; | ||
1648 | |||
1649 | case SKL_DIR_OUT: | ||
1650 | dst_fmt = mconfig->out_fmt; | ||
1651 | dst_fmt += pin_count; | ||
1652 | break; | ||
1653 | |||
1654 | default: | ||
1655 | dev_err(dev, "Invalid direction value\n"); | ||
1656 | return -EINVAL; | ||
1657 | } | ||
1658 | |||
1659 | switch (tkn) { | ||
1660 | case SKL_TKN_U32_FMT_CH: | ||
1661 | dst_fmt->channels = value; | ||
1662 | break; | ||
1663 | |||
1664 | case SKL_TKN_U32_FMT_FREQ: | ||
1665 | dst_fmt->s_freq = value; | ||
1666 | break; | ||
1667 | |||
1668 | case SKL_TKN_U32_FMT_BIT_DEPTH: | ||
1669 | dst_fmt->bit_depth = value; | ||
1670 | break; | ||
1671 | |||
1672 | case SKL_TKN_U32_FMT_SAMPLE_SIZE: | ||
1673 | dst_fmt->valid_bit_depth = value; | ||
1674 | break; | ||
1675 | |||
1676 | case SKL_TKN_U32_FMT_CH_CONFIG: | ||
1677 | dst_fmt->ch_cfg = value; | ||
1678 | break; | ||
1679 | |||
1680 | case SKL_TKN_U32_FMT_INTERLEAVE: | ||
1681 | dst_fmt->interleaving_style = value; | ||
1682 | break; | ||
1683 | |||
1684 | case SKL_TKN_U32_FMT_SAMPLE_TYPE: | ||
1685 | dst_fmt->sample_type = value; | ||
1686 | break; | ||
1687 | |||
1688 | case SKL_TKN_U32_FMT_CH_MAP: | ||
1689 | dst_fmt->ch_map = value; | ||
1690 | break; | ||
1691 | |||
1692 | default: | ||
1693 | dev_err(dev, "Invalid token %d\n", tkn); | ||
1694 | return -EINVAL; | ||
1695 | } | ||
1696 | |||
1697 | return 0; | ||
1524 | } | 1698 | } |
1525 | 1699 | ||
1526 | static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt, | 1700 | static int skl_tplg_get_uuid(struct device *dev, struct skl_module_cfg *mconfig, |
1527 | struct skl_dfw_module_fmt *src_fmt, | 1701 | struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn) |
1528 | int pins) | 1702 | { |
1703 | if (uuid_tkn->token == SKL_TKN_UUID) | ||
1704 | memcpy(&mconfig->guid, &uuid_tkn->uuid, 16); | ||
1705 | else { | ||
1706 | dev_err(dev, "Not an UUID token tkn %d\n", uuid_tkn->token); | ||
1707 | return -EINVAL; | ||
1708 | } | ||
1709 | |||
1710 | return 0; | ||
1711 | } | ||
1712 | |||
1713 | static void skl_tplg_fill_pin_dynamic_val( | ||
1714 | struct skl_module_pin *mpin, u32 pin_count, u32 value) | ||
1529 | { | 1715 | { |
1530 | int i; | 1716 | int i; |
1531 | 1717 | ||
1532 | for (i = 0; i < pins; i++) { | 1718 | for (i = 0; i < pin_count; i++) |
1533 | dst_fmt[i].channels = src_fmt[i].channels; | 1719 | mpin[i].is_dynamic = value; |
1534 | dst_fmt[i].s_freq = src_fmt[i].freq; | 1720 | } |
1535 | dst_fmt[i].bit_depth = src_fmt[i].bit_depth; | 1721 | |
1536 | dst_fmt[i].valid_bit_depth = src_fmt[i].valid_bit_depth; | 1722 | /* |
1537 | dst_fmt[i].ch_cfg = src_fmt[i].ch_cfg; | 1723 | * Parse tokens to fill up the module private data |
1538 | dst_fmt[i].ch_map = src_fmt[i].ch_map; | 1724 | */ |
1539 | dst_fmt[i].interleaving_style = src_fmt[i].interleaving_style; | 1725 | static int skl_tplg_get_token(struct device *dev, |
1540 | dst_fmt[i].sample_type = src_fmt[i].sample_type; | 1726 | struct snd_soc_tplg_vendor_value_elem *tkn_elem, |
1727 | struct skl *skl, struct skl_module_cfg *mconfig) | ||
1728 | { | ||
1729 | int tkn_count = 0; | ||
1730 | int ret; | ||
1731 | static int is_pipe_exists; | ||
1732 | static int pin_index, dir; | ||
1733 | |||
1734 | if (tkn_elem->token > SKL_TKN_MAX) | ||
1735 | return -EINVAL; | ||
1736 | |||
1737 | switch (tkn_elem->token) { | ||
1738 | case SKL_TKN_U8_IN_QUEUE_COUNT: | ||
1739 | mconfig->max_in_queue = tkn_elem->value; | ||
1740 | mconfig->m_in_pin = devm_kzalloc(dev, mconfig->max_in_queue * | ||
1741 | sizeof(*mconfig->m_in_pin), | ||
1742 | GFP_KERNEL); | ||
1743 | if (!mconfig->m_in_pin) | ||
1744 | return -ENOMEM; | ||
1745 | |||
1746 | break; | ||
1747 | |||
1748 | case SKL_TKN_U8_OUT_QUEUE_COUNT: | ||
1749 | mconfig->max_out_queue = tkn_elem->value; | ||
1750 | mconfig->m_out_pin = devm_kzalloc(dev, mconfig->max_out_queue * | ||
1751 | sizeof(*mconfig->m_out_pin), | ||
1752 | GFP_KERNEL); | ||
1753 | |||
1754 | if (!mconfig->m_out_pin) | ||
1755 | return -ENOMEM; | ||
1756 | |||
1757 | break; | ||
1758 | |||
1759 | case SKL_TKN_U8_DYN_IN_PIN: | ||
1760 | if (!mconfig->m_in_pin) | ||
1761 | return -ENOMEM; | ||
1762 | |||
1763 | skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, | ||
1764 | mconfig->max_in_queue, tkn_elem->value); | ||
1765 | |||
1766 | break; | ||
1767 | |||
1768 | case SKL_TKN_U8_DYN_OUT_PIN: | ||
1769 | if (!mconfig->m_out_pin) | ||
1770 | return -ENOMEM; | ||
1771 | |||
1772 | skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, | ||
1773 | mconfig->max_out_queue, tkn_elem->value); | ||
1774 | |||
1775 | break; | ||
1776 | |||
1777 | case SKL_TKN_U8_TIME_SLOT: | ||
1778 | mconfig->time_slot = tkn_elem->value; | ||
1779 | break; | ||
1780 | |||
1781 | case SKL_TKN_U8_CORE_ID: | ||
1782 | mconfig->core_id = tkn_elem->value; | ||
1783 | |||
1784 | case SKL_TKN_U8_MOD_TYPE: | ||
1785 | mconfig->m_type = tkn_elem->value; | ||
1786 | break; | ||
1787 | |||
1788 | case SKL_TKN_U8_DEV_TYPE: | ||
1789 | mconfig->dev_type = tkn_elem->value; | ||
1790 | break; | ||
1791 | |||
1792 | case SKL_TKN_U8_HW_CONN_TYPE: | ||
1793 | mconfig->hw_conn_type = tkn_elem->value; | ||
1794 | break; | ||
1795 | |||
1796 | case SKL_TKN_U16_MOD_INST_ID: | ||
1797 | mconfig->id.instance_id = | ||
1798 | tkn_elem->value; | ||
1799 | break; | ||
1800 | |||
1801 | case SKL_TKN_U32_MEM_PAGES: | ||
1802 | mconfig->mem_pages = tkn_elem->value; | ||
1803 | break; | ||
1804 | |||
1805 | case SKL_TKN_U32_MAX_MCPS: | ||
1806 | mconfig->mcps = tkn_elem->value; | ||
1807 | break; | ||
1808 | |||
1809 | case SKL_TKN_U32_OBS: | ||
1810 | mconfig->obs = tkn_elem->value; | ||
1811 | break; | ||
1812 | |||
1813 | case SKL_TKN_U32_IBS: | ||
1814 | mconfig->ibs = tkn_elem->value; | ||
1815 | break; | ||
1816 | |||
1817 | case SKL_TKN_U32_VBUS_ID: | ||
1818 | mconfig->vbus_id = tkn_elem->value; | ||
1819 | break; | ||
1820 | |||
1821 | case SKL_TKN_U32_PARAMS_FIXUP: | ||
1822 | mconfig->params_fixup = tkn_elem->value; | ||
1823 | break; | ||
1824 | |||
1825 | case SKL_TKN_U32_CONVERTER: | ||
1826 | mconfig->converter = tkn_elem->value; | ||
1827 | break; | ||
1828 | |||
1829 | case SKL_TKN_U32_PIPE_ID: | ||
1830 | ret = skl_tplg_add_pipe(dev, | ||
1831 | mconfig, skl, tkn_elem); | ||
1832 | |||
1833 | if (ret < 0) | ||
1834 | return is_pipe_exists; | ||
1835 | |||
1836 | if (ret == EEXIST) | ||
1837 | is_pipe_exists = 1; | ||
1838 | |||
1839 | break; | ||
1840 | |||
1841 | case SKL_TKN_U32_PIPE_CONN_TYPE: | ||
1842 | case SKL_TKN_U32_PIPE_PRIORITY: | ||
1843 | case SKL_TKN_U32_PIPE_MEM_PGS: | ||
1844 | if (is_pipe_exists) { | ||
1845 | ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe, | ||
1846 | tkn_elem->token, tkn_elem->value); | ||
1847 | if (ret < 0) | ||
1848 | return ret; | ||
1849 | } | ||
1850 | |||
1851 | break; | ||
1852 | |||
1853 | /* | ||
1854 | * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both | ||
1855 | * direction and the pin count. The first four bits represent | ||
1856 | * direction and next four the pin count. | ||
1857 | */ | ||
1858 | case SKL_TKN_U32_DIR_PIN_COUNT: | ||
1859 | dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK; | ||
1860 | pin_index = (tkn_elem->value & | ||
1861 | SKL_PIN_COUNT_MASK) >> 4; | ||
1862 | |||
1863 | break; | ||
1864 | |||
1865 | case SKL_TKN_U32_FMT_CH: | ||
1866 | case SKL_TKN_U32_FMT_FREQ: | ||
1867 | case SKL_TKN_U32_FMT_BIT_DEPTH: | ||
1868 | case SKL_TKN_U32_FMT_SAMPLE_SIZE: | ||
1869 | case SKL_TKN_U32_FMT_CH_CONFIG: | ||
1870 | case SKL_TKN_U32_FMT_INTERLEAVE: | ||
1871 | case SKL_TKN_U32_FMT_SAMPLE_TYPE: | ||
1872 | case SKL_TKN_U32_FMT_CH_MAP: | ||
1873 | ret = skl_tplg_fill_fmt(dev, mconfig, tkn_elem->token, | ||
1874 | tkn_elem->value, dir, pin_index); | ||
1875 | |||
1876 | if (ret < 0) | ||
1877 | return ret; | ||
1878 | |||
1879 | break; | ||
1880 | |||
1881 | case SKL_TKN_U32_PIN_MOD_ID: | ||
1882 | case SKL_TKN_U32_PIN_INST_ID: | ||
1883 | ret = skl_tplg_fill_pins_info(dev, | ||
1884 | mconfig, tkn_elem, dir, | ||
1885 | pin_index); | ||
1886 | if (ret < 0) | ||
1887 | return ret; | ||
1888 | |||
1889 | break; | ||
1890 | |||
1891 | case SKL_TKN_U32_CAPS_SIZE: | ||
1892 | mconfig->formats_config.caps_size = | ||
1893 | tkn_elem->value; | ||
1894 | |||
1895 | break; | ||
1896 | |||
1897 | case SKL_TKN_U32_PROC_DOMAIN: | ||
1898 | mconfig->domain = | ||
1899 | tkn_elem->value; | ||
1900 | |||
1901 | break; | ||
1902 | |||
1903 | case SKL_TKN_U8_IN_PIN_TYPE: | ||
1904 | case SKL_TKN_U8_OUT_PIN_TYPE: | ||
1905 | case SKL_TKN_U8_CONN_TYPE: | ||
1906 | break; | ||
1907 | |||
1908 | default: | ||
1909 | dev_err(dev, "Token %d not handled\n", | ||
1910 | tkn_elem->token); | ||
1911 | return -EINVAL; | ||
1912 | } | ||
1913 | |||
1914 | tkn_count++; | ||
1915 | |||
1916 | return tkn_count; | ||
1917 | } | ||
1918 | |||
1919 | /* | ||
1920 | * Parse the vendor array for specific tokens to construct | ||
1921 | * module private data | ||
1922 | */ | ||
1923 | static int skl_tplg_get_tokens(struct device *dev, | ||
1924 | char *pvt_data, struct skl *skl, | ||
1925 | struct skl_module_cfg *mconfig, int block_size) | ||
1926 | { | ||
1927 | struct snd_soc_tplg_vendor_array *array; | ||
1928 | struct snd_soc_tplg_vendor_value_elem *tkn_elem; | ||
1929 | int tkn_count = 0, ret; | ||
1930 | int off = 0, tuple_size = 0; | ||
1931 | |||
1932 | if (block_size <= 0) | ||
1933 | return -EINVAL; | ||
1934 | |||
1935 | while (tuple_size < block_size) { | ||
1936 | array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); | ||
1937 | |||
1938 | off += array->size; | ||
1939 | |||
1940 | switch (array->type) { | ||
1941 | case SND_SOC_TPLG_TUPLE_TYPE_STRING: | ||
1942 | dev_warn(dev, "no string tokens expected for skl tplg\n"); | ||
1943 | continue; | ||
1944 | |||
1945 | case SND_SOC_TPLG_TUPLE_TYPE_UUID: | ||
1946 | ret = skl_tplg_get_uuid(dev, mconfig, array->uuid); | ||
1947 | if (ret < 0) | ||
1948 | return ret; | ||
1949 | |||
1950 | tuple_size += sizeof(*array->uuid); | ||
1951 | |||
1952 | continue; | ||
1953 | |||
1954 | default: | ||
1955 | tkn_elem = array->value; | ||
1956 | tkn_count = 0; | ||
1957 | break; | ||
1958 | } | ||
1959 | |||
1960 | while (tkn_count <= (array->num_elems - 1)) { | ||
1961 | ret = skl_tplg_get_token(dev, tkn_elem, | ||
1962 | skl, mconfig); | ||
1963 | |||
1964 | if (ret < 0) | ||
1965 | return ret; | ||
1966 | |||
1967 | tkn_count = tkn_count + ret; | ||
1968 | tkn_elem++; | ||
1969 | } | ||
1970 | |||
1971 | tuple_size += tkn_count * sizeof(*tkn_elem); | ||
1972 | } | ||
1973 | |||
1974 | return 0; | ||
1975 | } | ||
1976 | |||
1977 | /* | ||
1978 | * Every data block is preceded by a descriptor to read the number | ||
1979 | * of data blocks, they type of the block and it's size | ||
1980 | */ | ||
1981 | static int skl_tplg_get_desc_blocks(struct device *dev, | ||
1982 | struct snd_soc_tplg_vendor_array *array) | ||
1983 | { | ||
1984 | struct snd_soc_tplg_vendor_value_elem *tkn_elem; | ||
1985 | |||
1986 | tkn_elem = array->value; | ||
1987 | |||
1988 | switch (tkn_elem->token) { | ||
1989 | case SKL_TKN_U8_NUM_BLOCKS: | ||
1990 | case SKL_TKN_U8_BLOCK_TYPE: | ||
1991 | case SKL_TKN_U16_BLOCK_SIZE: | ||
1992 | return tkn_elem->value; | ||
1993 | |||
1994 | default: | ||
1995 | dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token); | ||
1996 | break; | ||
1997 | } | ||
1998 | |||
1999 | return -EINVAL; | ||
2000 | } | ||
2001 | |||
2002 | /* | ||
2003 | * Parse the private data for the token and corresponding value. | ||
2004 | * The private data can have multiple data blocks. So, a data block | ||
2005 | * is preceded by a descriptor for number of blocks and a descriptor | ||
2006 | * for the type and size of the suceeding data block. | ||
2007 | */ | ||
2008 | static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, | ||
2009 | struct skl *skl, struct device *dev, | ||
2010 | struct skl_module_cfg *mconfig) | ||
2011 | { | ||
2012 | struct snd_soc_tplg_vendor_array *array; | ||
2013 | int num_blocks, block_size = 0, block_type, off = 0; | ||
2014 | char *data; | ||
2015 | int ret; | ||
2016 | |||
2017 | /* Read the NUM_DATA_BLOCKS descriptor */ | ||
2018 | array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data; | ||
2019 | ret = skl_tplg_get_desc_blocks(dev, array); | ||
2020 | if (ret < 0) | ||
2021 | return ret; | ||
2022 | num_blocks = ret; | ||
2023 | |||
2024 | off += array->size; | ||
2025 | array = (struct snd_soc_tplg_vendor_array *)(tplg_w->priv.data + off); | ||
2026 | |||
2027 | /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ | ||
2028 | while (num_blocks > 0) { | ||
2029 | ret = skl_tplg_get_desc_blocks(dev, array); | ||
2030 | |||
2031 | if (ret < 0) | ||
2032 | return ret; | ||
2033 | block_type = ret; | ||
2034 | off += array->size; | ||
2035 | |||
2036 | array = (struct snd_soc_tplg_vendor_array *) | ||
2037 | (tplg_w->priv.data + off); | ||
2038 | |||
2039 | ret = skl_tplg_get_desc_blocks(dev, array); | ||
2040 | |||
2041 | if (ret < 0) | ||
2042 | return ret; | ||
2043 | block_size = ret; | ||
2044 | off += array->size; | ||
2045 | |||
2046 | array = (struct snd_soc_tplg_vendor_array *) | ||
2047 | (tplg_w->priv.data + off); | ||
2048 | |||
2049 | data = (tplg_w->priv.data + off); | ||
2050 | |||
2051 | if (block_type == SKL_TYPE_TUPLE) { | ||
2052 | ret = skl_tplg_get_tokens(dev, data, | ||
2053 | skl, mconfig, block_size); | ||
2054 | |||
2055 | if (ret < 0) | ||
2056 | return ret; | ||
2057 | |||
2058 | --num_blocks; | ||
2059 | } else { | ||
2060 | if (mconfig->formats_config.caps_size > 0) | ||
2061 | memcpy(mconfig->formats_config.caps, data, | ||
2062 | mconfig->formats_config.caps_size); | ||
2063 | --num_blocks; | ||
2064 | } | ||
1541 | } | 2065 | } |
2066 | |||
2067 | return 0; | ||
1542 | } | 2068 | } |
1543 | 2069 | ||
1544 | static void skl_clear_pin_config(struct snd_soc_platform *platform, | 2070 | static void skl_clear_pin_config(struct snd_soc_platform *platform, |
@@ -1606,9 +2132,6 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, | |||
1606 | struct skl *skl = ebus_to_skl(ebus); | 2132 | struct skl *skl = ebus_to_skl(ebus); |
1607 | struct hdac_bus *bus = ebus_to_hbus(ebus); | 2133 | struct hdac_bus *bus = ebus_to_hbus(ebus); |
1608 | struct skl_module_cfg *mconfig; | 2134 | struct skl_module_cfg *mconfig; |
1609 | struct skl_pipe *pipe; | ||
1610 | struct skl_dfw_module *dfw_config = | ||
1611 | (struct skl_dfw_module *)tplg_w->priv.data; | ||
1612 | 2135 | ||
1613 | if (!tplg_w->priv.size) | 2136 | if (!tplg_w->priv.size) |
1614 | goto bind_event; | 2137 | goto bind_event; |
@@ -1619,76 +2142,17 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, | |||
1619 | return -ENOMEM; | 2142 | return -ENOMEM; |
1620 | 2143 | ||
1621 | w->priv = mconfig; | 2144 | w->priv = mconfig; |
1622 | memcpy(&mconfig->guid, &dfw_config->uuid, 16); | ||
1623 | 2145 | ||
1624 | ret = snd_skl_get_module_info(skl->skl_sst, mconfig->guid, dfw_config); | 2146 | /* |
2147 | * module binary can be loaded later, so set it to query when | ||
2148 | * module is load for a use case | ||
2149 | */ | ||
2150 | mconfig->id.module_id = -1; | ||
2151 | |||
2152 | /* Parse private data for tuples */ | ||
2153 | ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig); | ||
1625 | if (ret < 0) | 2154 | if (ret < 0) |
1626 | return ret; | 2155 | return ret; |
1627 | |||
1628 | mconfig->id.module_id = dfw_config->module_id; | ||
1629 | mconfig->id.instance_id = dfw_config->instance_id; | ||
1630 | mconfig->mcps = dfw_config->max_mcps; | ||
1631 | mconfig->ibs = dfw_config->ibs; | ||
1632 | mconfig->obs = dfw_config->obs; | ||
1633 | mconfig->core_id = dfw_config->core_id; | ||
1634 | mconfig->max_in_queue = dfw_config->max_in_queue; | ||
1635 | mconfig->max_out_queue = dfw_config->max_out_queue; | ||
1636 | mconfig->is_loadable = dfw_config->is_loadable; | ||
1637 | skl_tplg_fill_fmt(mconfig->in_fmt, dfw_config->in_fmt, | ||
1638 | MODULE_MAX_IN_PINS); | ||
1639 | skl_tplg_fill_fmt(mconfig->out_fmt, dfw_config->out_fmt, | ||
1640 | MODULE_MAX_OUT_PINS); | ||
1641 | |||
1642 | mconfig->params_fixup = dfw_config->params_fixup; | ||
1643 | mconfig->converter = dfw_config->converter; | ||
1644 | mconfig->m_type = dfw_config->module_type; | ||
1645 | mconfig->vbus_id = dfw_config->vbus_id; | ||
1646 | mconfig->mem_pages = dfw_config->mem_pages; | ||
1647 | |||
1648 | pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe); | ||
1649 | if (pipe) | ||
1650 | mconfig->pipe = pipe; | ||
1651 | |||
1652 | mconfig->dev_type = dfw_config->dev_type; | ||
1653 | mconfig->hw_conn_type = dfw_config->hw_conn_type; | ||
1654 | mconfig->time_slot = dfw_config->time_slot; | ||
1655 | mconfig->formats_config.caps_size = dfw_config->caps.caps_size; | ||
1656 | |||
1657 | mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) * | ||
1658 | sizeof(*mconfig->m_in_pin), | ||
1659 | GFP_KERNEL); | ||
1660 | if (!mconfig->m_in_pin) | ||
1661 | return -ENOMEM; | ||
1662 | |||
1663 | mconfig->m_out_pin = devm_kzalloc(bus->dev, (mconfig->max_out_queue) * | ||
1664 | sizeof(*mconfig->m_out_pin), | ||
1665 | GFP_KERNEL); | ||
1666 | if (!mconfig->m_out_pin) | ||
1667 | return -ENOMEM; | ||
1668 | |||
1669 | skl_fill_module_pin_info(dfw_config->in_pin, mconfig->m_in_pin, | ||
1670 | dfw_config->is_dynamic_in_pin, | ||
1671 | mconfig->max_in_queue); | ||
1672 | |||
1673 | skl_fill_module_pin_info(dfw_config->out_pin, mconfig->m_out_pin, | ||
1674 | dfw_config->is_dynamic_out_pin, | ||
1675 | mconfig->max_out_queue); | ||
1676 | |||
1677 | |||
1678 | if (mconfig->formats_config.caps_size == 0) | ||
1679 | goto bind_event; | ||
1680 | |||
1681 | mconfig->formats_config.caps = (u32 *)devm_kzalloc(bus->dev, | ||
1682 | mconfig->formats_config.caps_size, GFP_KERNEL); | ||
1683 | |||
1684 | if (mconfig->formats_config.caps == NULL) | ||
1685 | return -ENOMEM; | ||
1686 | |||
1687 | memcpy(mconfig->formats_config.caps, dfw_config->caps.caps, | ||
1688 | dfw_config->caps.caps_size); | ||
1689 | mconfig->formats_config.param_id = dfw_config->caps.param_id; | ||
1690 | mconfig->formats_config.set_params = dfw_config->caps.set_params; | ||
1691 | |||
1692 | bind_event: | 2156 | bind_event: |
1693 | if (tplg_w->event_type == 0) { | 2157 | if (tplg_w->event_type == 0) { |
1694 | dev_dbg(bus->dev, "ASoC: No event handler required\n"); | 2158 | dev_dbg(bus->dev, "ASoC: No event handler required\n"); |
@@ -1767,11 +2231,229 @@ static int skl_tplg_control_load(struct snd_soc_component *cmpnt, | |||
1767 | return 0; | 2231 | return 0; |
1768 | } | 2232 | } |
1769 | 2233 | ||
2234 | static int skl_tplg_fill_str_mfest_tkn(struct device *dev, | ||
2235 | struct snd_soc_tplg_vendor_string_elem *str_elem, | ||
2236 | struct skl_dfw_manifest *minfo) | ||
2237 | { | ||
2238 | int tkn_count = 0; | ||
2239 | static int ref_count; | ||
2240 | |||
2241 | switch (str_elem->token) { | ||
2242 | case SKL_TKN_STR_LIB_NAME: | ||
2243 | if (ref_count > minfo->lib_count - 1) { | ||
2244 | ref_count = 0; | ||
2245 | return -EINVAL; | ||
2246 | } | ||
2247 | |||
2248 | strncpy(minfo->lib[ref_count].name, str_elem->string, | ||
2249 | ARRAY_SIZE(minfo->lib[ref_count].name)); | ||
2250 | ref_count++; | ||
2251 | tkn_count++; | ||
2252 | break; | ||
2253 | |||
2254 | default: | ||
2255 | dev_err(dev, "Not a string token %d\n", str_elem->token); | ||
2256 | break; | ||
2257 | } | ||
2258 | |||
2259 | return tkn_count; | ||
2260 | } | ||
2261 | |||
2262 | static int skl_tplg_get_str_tkn(struct device *dev, | ||
2263 | struct snd_soc_tplg_vendor_array *array, | ||
2264 | struct skl_dfw_manifest *minfo) | ||
2265 | { | ||
2266 | int tkn_count = 0, ret; | ||
2267 | struct snd_soc_tplg_vendor_string_elem *str_elem; | ||
2268 | |||
2269 | str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value; | ||
2270 | while (tkn_count < array->num_elems) { | ||
2271 | ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, minfo); | ||
2272 | str_elem++; | ||
2273 | |||
2274 | if (ret < 0) | ||
2275 | return ret; | ||
2276 | |||
2277 | tkn_count = tkn_count + ret; | ||
2278 | } | ||
2279 | |||
2280 | return tkn_count; | ||
2281 | } | ||
2282 | |||
2283 | static int skl_tplg_get_int_tkn(struct device *dev, | ||
2284 | struct snd_soc_tplg_vendor_value_elem *tkn_elem, | ||
2285 | struct skl_dfw_manifest *minfo) | ||
2286 | { | ||
2287 | int tkn_count = 0; | ||
2288 | |||
2289 | switch (tkn_elem->token) { | ||
2290 | case SKL_TKN_U32_LIB_COUNT: | ||
2291 | minfo->lib_count = tkn_elem->value; | ||
2292 | tkn_count++; | ||
2293 | break; | ||
2294 | |||
2295 | default: | ||
2296 | dev_err(dev, "Not a manifest token %d\n", tkn_elem->token); | ||
2297 | return -EINVAL; | ||
2298 | } | ||
2299 | |||
2300 | return tkn_count; | ||
2301 | } | ||
2302 | |||
2303 | /* | ||
2304 | * Fill the manifest structure by parsing the tokens based on the | ||
2305 | * type. | ||
2306 | */ | ||
2307 | static int skl_tplg_get_manifest_tkn(struct device *dev, | ||
2308 | char *pvt_data, struct skl_dfw_manifest *minfo, | ||
2309 | int block_size) | ||
2310 | { | ||
2311 | int tkn_count = 0, ret; | ||
2312 | int off = 0, tuple_size = 0; | ||
2313 | struct snd_soc_tplg_vendor_array *array; | ||
2314 | struct snd_soc_tplg_vendor_value_elem *tkn_elem; | ||
2315 | |||
2316 | if (block_size <= 0) | ||
2317 | return -EINVAL; | ||
2318 | |||
2319 | while (tuple_size < block_size) { | ||
2320 | array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); | ||
2321 | off += array->size; | ||
2322 | switch (array->type) { | ||
2323 | case SND_SOC_TPLG_TUPLE_TYPE_STRING: | ||
2324 | ret = skl_tplg_get_str_tkn(dev, array, minfo); | ||
2325 | |||
2326 | if (ret < 0) | ||
2327 | return ret; | ||
2328 | tkn_count += ret; | ||
2329 | |||
2330 | tuple_size += tkn_count * | ||
2331 | sizeof(struct snd_soc_tplg_vendor_string_elem); | ||
2332 | continue; | ||
2333 | |||
2334 | case SND_SOC_TPLG_TUPLE_TYPE_UUID: | ||
2335 | dev_warn(dev, "no uuid tokens for skl tplf manifest\n"); | ||
2336 | continue; | ||
2337 | |||
2338 | default: | ||
2339 | tkn_elem = array->value; | ||
2340 | tkn_count = 0; | ||
2341 | break; | ||
2342 | } | ||
2343 | |||
2344 | while (tkn_count <= array->num_elems - 1) { | ||
2345 | ret = skl_tplg_get_int_tkn(dev, | ||
2346 | tkn_elem, minfo); | ||
2347 | if (ret < 0) | ||
2348 | return ret; | ||
2349 | |||
2350 | tkn_count = tkn_count + ret; | ||
2351 | tkn_elem++; | ||
2352 | tuple_size += tkn_count * | ||
2353 | sizeof(struct snd_soc_tplg_vendor_value_elem); | ||
2354 | break; | ||
2355 | } | ||
2356 | tkn_count = 0; | ||
2357 | } | ||
2358 | |||
2359 | return 0; | ||
2360 | } | ||
2361 | |||
2362 | /* | ||
2363 | * Parse manifest private data for tokens. The private data block is | ||
2364 | * preceded by descriptors for type and size of data block. | ||
2365 | */ | ||
2366 | static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, | ||
2367 | struct device *dev, struct skl_dfw_manifest *minfo) | ||
2368 | { | ||
2369 | struct snd_soc_tplg_vendor_array *array; | ||
2370 | int num_blocks, block_size = 0, block_type, off = 0; | ||
2371 | char *data; | ||
2372 | int ret; | ||
2373 | |||
2374 | /* Read the NUM_DATA_BLOCKS descriptor */ | ||
2375 | array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data; | ||
2376 | ret = skl_tplg_get_desc_blocks(dev, array); | ||
2377 | if (ret < 0) | ||
2378 | return ret; | ||
2379 | num_blocks = ret; | ||
2380 | |||
2381 | off += array->size; | ||
2382 | array = (struct snd_soc_tplg_vendor_array *) | ||
2383 | (manifest->priv.data + off); | ||
2384 | |||
2385 | /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ | ||
2386 | while (num_blocks > 0) { | ||
2387 | ret = skl_tplg_get_desc_blocks(dev, array); | ||
2388 | |||
2389 | if (ret < 0) | ||
2390 | return ret; | ||
2391 | block_type = ret; | ||
2392 | off += array->size; | ||
2393 | |||
2394 | array = (struct snd_soc_tplg_vendor_array *) | ||
2395 | (manifest->priv.data + off); | ||
2396 | |||
2397 | ret = skl_tplg_get_desc_blocks(dev, array); | ||
2398 | |||
2399 | if (ret < 0) | ||
2400 | return ret; | ||
2401 | block_size = ret; | ||
2402 | off += array->size; | ||
2403 | |||
2404 | array = (struct snd_soc_tplg_vendor_array *) | ||
2405 | (manifest->priv.data + off); | ||
2406 | |||
2407 | data = (manifest->priv.data + off); | ||
2408 | |||
2409 | if (block_type == SKL_TYPE_TUPLE) { | ||
2410 | ret = skl_tplg_get_manifest_tkn(dev, data, minfo, | ||
2411 | block_size); | ||
2412 | |||
2413 | if (ret < 0) | ||
2414 | return ret; | ||
2415 | |||
2416 | --num_blocks; | ||
2417 | } else { | ||
2418 | return -EINVAL; | ||
2419 | } | ||
2420 | } | ||
2421 | |||
2422 | return 0; | ||
2423 | } | ||
2424 | |||
2425 | static int skl_manifest_load(struct snd_soc_component *cmpnt, | ||
2426 | struct snd_soc_tplg_manifest *manifest) | ||
2427 | { | ||
2428 | struct skl_dfw_manifest *minfo; | ||
2429 | struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); | ||
2430 | struct hdac_bus *bus = ebus_to_hbus(ebus); | ||
2431 | struct skl *skl = ebus_to_skl(ebus); | ||
2432 | int ret = 0; | ||
2433 | |||
2434 | /* proceed only if we have private data defined */ | ||
2435 | if (manifest->priv.size == 0) | ||
2436 | return 0; | ||
2437 | |||
2438 | minfo = &skl->skl_sst->manifest; | ||
2439 | |||
2440 | skl_tplg_get_manifest_data(manifest, bus->dev, minfo); | ||
2441 | |||
2442 | if (minfo->lib_count > HDA_MAX_LIB) { | ||
2443 | dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", | ||
2444 | minfo->lib_count); | ||
2445 | ret = -EINVAL; | ||
2446 | } | ||
2447 | |||
2448 | return ret; | ||
2449 | } | ||
2450 | |||
1770 | static struct snd_soc_tplg_ops skl_tplg_ops = { | 2451 | static struct snd_soc_tplg_ops skl_tplg_ops = { |
1771 | .widget_load = skl_tplg_widget_load, | 2452 | .widget_load = skl_tplg_widget_load, |
1772 | .control_load = skl_tplg_control_load, | 2453 | .control_load = skl_tplg_control_load, |
1773 | .bytes_ext_ops = skl_tlv_ops, | 2454 | .bytes_ext_ops = skl_tlv_ops, |
1774 | .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), | 2455 | .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), |
2456 | .manifest = skl_manifest_load, | ||
1775 | }; | 2457 | }; |
1776 | 2458 | ||
1777 | /* | 2459 | /* |
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 22d3ef83817d..a519360f42a6 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h | |||
@@ -133,7 +133,7 @@ struct skl_i2s_config_blob { | |||
133 | struct skl_dma_control { | 133 | struct skl_dma_control { |
134 | u32 node_id; | 134 | u32 node_id; |
135 | u32 config_length; | 135 | u32 config_length; |
136 | u32 config_data[1]; | 136 | u32 config_data[0]; |
137 | } __packed; | 137 | } __packed; |
138 | 138 | ||
139 | struct skl_cpr_cfg { | 139 | struct skl_cpr_cfg { |
@@ -215,9 +215,20 @@ struct skl_module_fmt { | |||
215 | 215 | ||
216 | struct skl_module_cfg; | 216 | struct skl_module_cfg; |
217 | 217 | ||
218 | struct skl_mod_inst_map { | ||
219 | u16 mod_id; | ||
220 | u16 inst_id; | ||
221 | }; | ||
222 | |||
223 | struct skl_kpb_params { | ||
224 | u32 num_modules; | ||
225 | struct skl_mod_inst_map map[0]; | ||
226 | }; | ||
227 | |||
218 | struct skl_module_inst_id { | 228 | struct skl_module_inst_id { |
219 | u32 module_id; | 229 | int module_id; |
220 | u32 instance_id; | 230 | u32 instance_id; |
231 | int pvt_id; | ||
221 | }; | 232 | }; |
222 | 233 | ||
223 | enum skl_module_pin_state { | 234 | enum skl_module_pin_state { |
diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index a32e5e9cc530..2f6281e056d6 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h | |||
@@ -80,7 +80,8 @@ enum skl_module_type { | |||
80 | SKL_MODULE_TYPE_UPDWMIX, | 80 | SKL_MODULE_TYPE_UPDWMIX, |
81 | SKL_MODULE_TYPE_SRCINT, | 81 | SKL_MODULE_TYPE_SRCINT, |
82 | SKL_MODULE_TYPE_ALGO, | 82 | SKL_MODULE_TYPE_ALGO, |
83 | SKL_MODULE_TYPE_BASE_OUTFMT | 83 | SKL_MODULE_TYPE_BASE_OUTFMT, |
84 | SKL_MODULE_TYPE_KPB, | ||
84 | }; | 85 | }; |
85 | 86 | ||
86 | enum skl_core_affinity { | 87 | enum skl_core_affinity { |
@@ -148,84 +149,34 @@ enum skl_module_param_type { | |||
148 | SKL_PARAM_BIND | 149 | SKL_PARAM_BIND |
149 | }; | 150 | }; |
150 | 151 | ||
151 | struct skl_dfw_module_pin { | 152 | struct skl_dfw_algo_data { |
152 | u16 module_id; | ||
153 | u16 instance_id; | ||
154 | } __packed; | ||
155 | |||
156 | struct skl_dfw_module_fmt { | ||
157 | u32 channels; | ||
158 | u32 freq; | ||
159 | u32 bit_depth; | ||
160 | u32 valid_bit_depth; | ||
161 | u32 ch_cfg; | ||
162 | u32 interleaving_style; | ||
163 | u32 sample_type; | ||
164 | u32 ch_map; | ||
165 | } __packed; | ||
166 | |||
167 | struct skl_dfw_module_caps { | ||
168 | u32 set_params:2; | 153 | u32 set_params:2; |
169 | u32 rsvd:30; | 154 | u32 rsvd:30; |
170 | u32 param_id; | 155 | u32 param_id; |
171 | u32 caps_size; | 156 | u32 max; |
172 | u32 caps[HDA_SST_CFG_MAX]; | 157 | char params[0]; |
173 | }; | ||
174 | |||
175 | struct skl_dfw_pipe { | ||
176 | u8 pipe_id; | ||
177 | u8 pipe_priority; | ||
178 | u16 conn_type:4; | ||
179 | u16 rsvd:4; | ||
180 | u16 memory_pages:8; | ||
181 | } __packed; | 158 | } __packed; |
182 | 159 | ||
183 | struct skl_dfw_module { | 160 | #define LIB_NAME_LENGTH 128 |
184 | u8 uuid[16]; | 161 | #define HDA_MAX_LIB 16 |
185 | 162 | ||
186 | u16 module_id; | 163 | struct lib_info { |
187 | u16 instance_id; | 164 | char name[LIB_NAME_LENGTH]; |
188 | u32 max_mcps; | ||
189 | u32 mem_pages; | ||
190 | u32 obs; | ||
191 | u32 ibs; | ||
192 | u32 vbus_id; | ||
193 | |||
194 | u32 max_in_queue:8; | ||
195 | u32 max_out_queue:8; | ||
196 | u32 time_slot:8; | ||
197 | u32 core_id:4; | ||
198 | u32 rsvd1:4; | ||
199 | |||
200 | u32 module_type:8; | ||
201 | u32 conn_type:4; | ||
202 | u32 dev_type:4; | ||
203 | u32 hw_conn_type:4; | ||
204 | u32 rsvd2:12; | ||
205 | |||
206 | u32 params_fixup:8; | ||
207 | u32 converter:8; | ||
208 | u32 input_pin_type:1; | ||
209 | u32 output_pin_type:1; | ||
210 | u32 is_dynamic_in_pin:1; | ||
211 | u32 is_dynamic_out_pin:1; | ||
212 | u32 is_loadable:1; | ||
213 | u32 rsvd3:11; | ||
214 | |||
215 | struct skl_dfw_pipe pipe; | ||
216 | struct skl_dfw_module_fmt in_fmt[MAX_IN_QUEUE]; | ||
217 | struct skl_dfw_module_fmt out_fmt[MAX_OUT_QUEUE]; | ||
218 | struct skl_dfw_module_pin in_pin[MAX_IN_QUEUE]; | ||
219 | struct skl_dfw_module_pin out_pin[MAX_OUT_QUEUE]; | ||
220 | struct skl_dfw_module_caps caps; | ||
221 | } __packed; | 165 | } __packed; |
222 | 166 | ||
223 | struct skl_dfw_algo_data { | 167 | struct skl_dfw_manifest { |
224 | u32 set_params:2; | 168 | u32 lib_count; |
225 | u32 rsvd:30; | 169 | struct lib_info lib[HDA_MAX_LIB]; |
226 | u32 param_id; | ||
227 | u32 max; | ||
228 | char params[0]; | ||
229 | } __packed; | 170 | } __packed; |
230 | 171 | ||
172 | enum skl_tkn_dir { | ||
173 | SKL_DIR_IN, | ||
174 | SKL_DIR_OUT | ||
175 | }; | ||
176 | |||
177 | enum skl_tuple_type { | ||
178 | SKL_TYPE_TUPLE, | ||
179 | SKL_TYPE_DATA | ||
180 | }; | ||
181 | |||
231 | #endif | 182 | #endif |
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index e3e764167765..2989c164dafe 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c | |||
@@ -587,7 +587,7 @@ static int skl_first_init(struct hdac_ext_bus *ebus) | |||
587 | return -ENXIO; | 587 | return -ENXIO; |
588 | } | 588 | } |
589 | 589 | ||
590 | snd_hdac_ext_bus_parse_capabilities(ebus); | 590 | snd_hdac_bus_parse_capabilities(bus); |
591 | 591 | ||
592 | if (skl_acquire_irq(ebus, 0) < 0) | 592 | if (skl_acquire_irq(ebus, 0) < 0) |
593 | return -EBUSY; | 593 | return -EBUSY; |
@@ -684,7 +684,7 @@ static int skl_probe(struct pci_dev *pci, | |||
684 | skl_dmic_data.dmic_num = skl_get_dmic_geo(skl); | 684 | skl_dmic_data.dmic_num = skl_get_dmic_geo(skl); |
685 | 685 | ||
686 | /* check if dsp is there */ | 686 | /* check if dsp is there */ |
687 | if (ebus->ppcap) { | 687 | if (bus->ppcap) { |
688 | err = skl_machine_device_register(skl, | 688 | err = skl_machine_device_register(skl, |
689 | (void *)pci_id->driver_data); | 689 | (void *)pci_id->driver_data); |
690 | if (err < 0) | 690 | if (err < 0) |
@@ -698,7 +698,7 @@ static int skl_probe(struct pci_dev *pci, | |||
698 | skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; | 698 | skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; |
699 | 699 | ||
700 | } | 700 | } |
701 | if (ebus->mlcap) | 701 | if (bus->mlcap) |
702 | snd_hdac_ext_bus_get_ml_capabilities(ebus); | 702 | snd_hdac_ext_bus_get_ml_capabilities(ebus); |
703 | 703 | ||
704 | /* create device for soc dmic */ | 704 | /* create device for soc dmic */ |
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 9064e5b0d676..5d4fbb094c48 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h | |||
@@ -105,6 +105,7 @@ struct skl_dsp_ops { | |||
105 | int irq, const char *fw_name, | 105 | int irq, const char *fw_name, |
106 | struct skl_dsp_loader_ops loader_ops, | 106 | struct skl_dsp_loader_ops loader_ops, |
107 | struct skl_sst **skl_sst); | 107 | struct skl_sst **skl_sst); |
108 | int (*init_fw)(struct device *dev, struct skl_sst *ctx); | ||
108 | void (*cleanup)(struct device *dev, struct skl_sst *ctx); | 109 | void (*cleanup)(struct device *dev, struct skl_sst *ctx); |
109 | }; | 110 | }; |
110 | 111 | ||
@@ -123,4 +124,5 @@ int skl_free_dsp(struct skl *skl); | |||
123 | int skl_suspend_dsp(struct skl *skl); | 124 | int skl_suspend_dsp(struct skl *skl); |
124 | int skl_resume_dsp(struct skl *skl); | 125 | int skl_resume_dsp(struct skl *skl); |
125 | void skl_cleanup_resources(struct skl *skl); | 126 | void skl_cleanup_resources(struct skl *skl); |
127 | const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); | ||
126 | #endif /* __SOUND_SOC_SKL_H */ | 128 | #endif /* __SOUND_SOC_SKL_H */ |