Merge tag 'x86_shstk_for_6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / drivers / soundwire / intel_ace2x.c
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 // Copyright(c) 2023 Intel Corporation. All rights reserved.
3
4 /*
5  * Soundwire Intel ops for LunarLake
6  */
7
8 #include <linux/acpi.h>
9 #include <linux/device.h>
10 #include <linux/soundwire/sdw_registers.h>
11 #include <linux/soundwire/sdw.h>
12 #include <linux/soundwire/sdw_intel.h>
13 #include <sound/hda-mlink.h>
14 #include "cadence_master.h"
15 #include "bus.h"
16 #include "intel.h"
17
18 /*
19  * shim vendor-specific (vs) ops
20  */
21
22 static void intel_shim_vs_init(struct sdw_intel *sdw)
23 {
24         void __iomem *shim_vs = sdw->link_res->shim_vs;
25         u16 act = 0;
26
27         u16p_replace_bits(&act, 0x1, SDW_SHIM2_INTEL_VS_ACTMCTL_DOAIS);
28         act |= SDW_SHIM2_INTEL_VS_ACTMCTL_DACTQE;
29         act |=  SDW_SHIM2_INTEL_VS_ACTMCTL_DODS;
30         intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_ACTMCTL, act);
31         usleep_range(10, 15);
32 }
33
34 static int intel_shim_check_wake(struct sdw_intel *sdw)
35 {
36         void __iomem *shim_vs;
37         u16 wake_sts;
38
39         shim_vs = sdw->link_res->shim_vs;
40         wake_sts = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS);
41
42         return wake_sts & SDW_SHIM2_INTEL_VS_WAKEEN_PWS;
43 }
44
45 static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
46 {
47         void __iomem *shim_vs = sdw->link_res->shim_vs;
48         u16 wake_en;
49         u16 wake_sts;
50
51         wake_en = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN);
52
53         if (wake_enable) {
54                 /* Enable the wakeup */
55                 wake_en |= SDW_SHIM2_INTEL_VS_WAKEEN_PWE;
56                 intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN, wake_en);
57         } else {
58                 /* Disable the wake up interrupt */
59                 wake_en &= ~SDW_SHIM2_INTEL_VS_WAKEEN_PWE;
60                 intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN, wake_en);
61
62                 /* Clear wake status (W1C) */
63                 wake_sts = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS);
64                 wake_sts |= SDW_SHIM2_INTEL_VS_WAKEEN_PWS;
65                 intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS, wake_sts);
66         }
67 }
68
69 static int intel_link_power_up(struct sdw_intel *sdw)
70 {
71         struct sdw_bus *bus = &sdw->cdns.bus;
72         struct sdw_master_prop *prop = &bus->prop;
73         u32 *shim_mask = sdw->link_res->shim_mask;
74         unsigned int link_id = sdw->instance;
75         u32 syncprd;
76         int ret;
77
78         mutex_lock(sdw->link_res->shim_lock);
79
80         if (!*shim_mask) {
81                 /* we first need to program the SyncPRD/CPU registers */
82                 dev_dbg(sdw->cdns.dev, "first link up, programming SYNCPRD\n");
83
84                 if (prop->mclk_freq % 6000000)
85                         syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
86                 else
87                         syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;
88
89                 ret =  hdac_bus_eml_sdw_set_syncprd_unlocked(sdw->link_res->hbus, syncprd);
90                 if (ret < 0) {
91                         dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_set_syncprd failed: %d\n",
92                                 __func__, ret);
93                         goto out;
94                 }
95         }
96
97         ret = hdac_bus_eml_sdw_power_up_unlocked(sdw->link_res->hbus, link_id);
98         if (ret < 0) {
99                 dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_up failed: %d\n",
100                         __func__, ret);
101                 goto out;
102         }
103
104         if (!*shim_mask) {
105                 /* SYNCPU will change once link is active */
106                 ret =  hdac_bus_eml_sdw_wait_syncpu_unlocked(sdw->link_res->hbus);
107                 if (ret < 0) {
108                         dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_wait_syncpu failed: %d\n",
109                                 __func__, ret);
110                         goto out;
111                 }
112         }
113
114         *shim_mask |= BIT(link_id);
115
116         sdw->cdns.link_up = true;
117
118         intel_shim_vs_init(sdw);
119
120 out:
121         mutex_unlock(sdw->link_res->shim_lock);
122
123         return ret;
124 }
125
126 static int intel_link_power_down(struct sdw_intel *sdw)
127 {
128         u32 *shim_mask = sdw->link_res->shim_mask;
129         unsigned int link_id = sdw->instance;
130         int ret;
131
132         mutex_lock(sdw->link_res->shim_lock);
133
134         sdw->cdns.link_up = false;
135
136         *shim_mask &= ~BIT(link_id);
137
138         ret = hdac_bus_eml_sdw_power_down_unlocked(sdw->link_res->hbus, link_id);
139         if (ret < 0) {
140                 dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_down failed: %d\n",
141                         __func__, ret);
142
143                 /*
144                  * we leave the sdw->cdns.link_up flag as false since we've disabled
145                  * the link at this point and cannot handle interrupts any longer.
146                  */
147         }
148
149         mutex_unlock(sdw->link_res->shim_lock);
150
151         return ret;
152 }
153
154 static void intel_sync_arm(struct sdw_intel *sdw)
155 {
156         unsigned int link_id = sdw->instance;
157
158         mutex_lock(sdw->link_res->shim_lock);
159
160         hdac_bus_eml_sdw_sync_arm_unlocked(sdw->link_res->hbus, link_id);
161
162         mutex_unlock(sdw->link_res->shim_lock);
163 }
164
165 static int intel_sync_go_unlocked(struct sdw_intel *sdw)
166 {
167         int ret;
168
169         ret = hdac_bus_eml_sdw_sync_go_unlocked(sdw->link_res->hbus);
170         if (ret < 0)
171                 dev_err(sdw->cdns.dev, "%s: SyncGO clear failed: %d\n", __func__, ret);
172
173         return ret;
174 }
175
176 static int intel_sync_go(struct sdw_intel *sdw)
177 {
178         int ret;
179
180         mutex_lock(sdw->link_res->shim_lock);
181
182         ret = intel_sync_go_unlocked(sdw);
183
184         mutex_unlock(sdw->link_res->shim_lock);
185
186         return ret;
187 }
188
189 static bool intel_check_cmdsync_unlocked(struct sdw_intel *sdw)
190 {
191         return hdac_bus_eml_sdw_check_cmdsync_unlocked(sdw->link_res->hbus);
192 }
193
194 /*
195  * DAI operations
196  */
197 static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
198 };
199
200 static const struct snd_soc_component_driver dai_component = {
201         .name                   = "soundwire",
202 };
203
204 /*
205  * PDI routines
206  */
207 static void intel_pdi_init(struct sdw_intel *sdw,
208                            struct sdw_cdns_stream_config *config)
209 {
210         void __iomem *shim = sdw->link_res->shim;
211         int pcm_cap;
212
213         /* PCM Stream Capability */
214         pcm_cap = intel_readw(shim, SDW_SHIM2_PCMSCAP);
215
216         config->pcm_bd = FIELD_GET(SDW_SHIM2_PCMSCAP_BSS, pcm_cap);
217         config->pcm_in = FIELD_GET(SDW_SHIM2_PCMSCAP_ISS, pcm_cap);
218         config->pcm_out = FIELD_GET(SDW_SHIM2_PCMSCAP_ISS, pcm_cap);
219
220         dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n",
221                 config->pcm_bd, config->pcm_in, config->pcm_out);
222 }
223
224 static int
225 intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num)
226 {
227         void __iomem *shim = sdw->link_res->shim;
228
229         /* zero based values for channel count in register */
230         return intel_readw(shim, SDW_SHIM2_PCMSYCHC(pdi_num)) + 1;
231 }
232
233 static void intel_pdi_get_ch_update(struct sdw_intel *sdw,
234                                     struct sdw_cdns_pdi *pdi,
235                                     unsigned int num_pdi,
236                                     unsigned int *num_ch)
237 {
238         int ch_count = 0;
239         int i;
240
241         for (i = 0; i < num_pdi; i++) {
242                 pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num);
243                 ch_count += pdi->ch_count;
244                 pdi++;
245         }
246
247         *num_ch = ch_count;
248 }
249
250 static void intel_pdi_stream_ch_update(struct sdw_intel *sdw,
251                                        struct sdw_cdns_streams *stream)
252 {
253         intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd,
254                                 &stream->num_ch_bd);
255
256         intel_pdi_get_ch_update(sdw, stream->in, stream->num_in,
257                                 &stream->num_ch_in);
258
259         intel_pdi_get_ch_update(sdw, stream->out, stream->num_out,
260                                 &stream->num_ch_out);
261 }
262
263 static int intel_create_dai(struct sdw_cdns *cdns,
264                             struct snd_soc_dai_driver *dais,
265                             enum intel_pdi_type type,
266                             u32 num, u32 off, u32 max_ch)
267 {
268         int i;
269
270         if (!num)
271                 return 0;
272
273         for (i = off; i < (off + num); i++) {
274                 dais[i].name = devm_kasprintf(cdns->dev, GFP_KERNEL,
275                                               "SDW%d Pin%d",
276                                               cdns->instance, i);
277                 if (!dais[i].name)
278                         return -ENOMEM;
279
280                 if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) {
281                         dais[i].playback.channels_min = 1;
282                         dais[i].playback.channels_max = max_ch;
283                 }
284
285                 if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) {
286                         dais[i].capture.channels_min = 1;
287                         dais[i].capture.channels_max = max_ch;
288                 }
289
290                 dais[i].ops = &intel_pcm_dai_ops;
291         }
292
293         return 0;
294 }
295
296 static int intel_register_dai(struct sdw_intel *sdw)
297 {
298         struct sdw_cdns_dai_runtime **dai_runtime_array;
299         struct sdw_cdns_stream_config config;
300         struct sdw_cdns *cdns = &sdw->cdns;
301         struct sdw_cdns_streams *stream;
302         struct snd_soc_dai_driver *dais;
303         int num_dai;
304         int ret;
305         int off = 0;
306
307         /* Read the PDI config and initialize cadence PDI */
308         intel_pdi_init(sdw, &config);
309         ret = sdw_cdns_pdi_init(cdns, config);
310         if (ret)
311                 return ret;
312
313         intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm);
314
315         /* DAIs are created based on total number of PDIs supported */
316         num_dai = cdns->pcm.num_pdi;
317
318         dai_runtime_array = devm_kcalloc(cdns->dev, num_dai,
319                                          sizeof(struct sdw_cdns_dai_runtime *),
320                                          GFP_KERNEL);
321         if (!dai_runtime_array)
322                 return -ENOMEM;
323         cdns->dai_runtime_array = dai_runtime_array;
324
325         dais = devm_kcalloc(cdns->dev, num_dai, sizeof(*dais), GFP_KERNEL);
326         if (!dais)
327                 return -ENOMEM;
328
329         /* Create PCM DAIs */
330         stream = &cdns->pcm;
331
332         ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pcm.num_in,
333                                off, stream->num_ch_in);
334         if (ret)
335                 return ret;
336
337         off += cdns->pcm.num_in;
338         ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pcm.num_out,
339                                off, stream->num_ch_out);
340         if (ret)
341                 return ret;
342
343         off += cdns->pcm.num_out;
344         ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pcm.num_bd,
345                                off, stream->num_ch_bd);
346         if (ret)
347                 return ret;
348
349         return devm_snd_soc_register_component(cdns->dev, &dai_component,
350                                                dais, num_dai);
351 }
352
353 static void intel_program_sdi(struct sdw_intel *sdw, int dev_num)
354 {
355         int ret;
356
357         ret = hdac_bus_eml_sdw_set_lsdiid(sdw->link_res->hbus, sdw->instance, dev_num);
358         if (ret < 0)
359                 dev_err(sdw->cdns.dev, "%s: could not set lsdiid for link %d %d\n",
360                         __func__, sdw->instance, dev_num);
361 }
362
363 const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops = {
364         .debugfs_init = intel_ace2x_debugfs_init,
365         .debugfs_exit = intel_ace2x_debugfs_exit,
366
367         .register_dai = intel_register_dai,
368
369         .check_clock_stop = intel_check_clock_stop,
370         .start_bus = intel_start_bus,
371         .start_bus_after_reset = intel_start_bus_after_reset,
372         .start_bus_after_clock_stop = intel_start_bus_after_clock_stop,
373         .stop_bus = intel_stop_bus,
374
375         .link_power_up = intel_link_power_up,
376         .link_power_down = intel_link_power_down,
377
378         .shim_check_wake = intel_shim_check_wake,
379         .shim_wake = intel_shim_wake,
380
381         .pre_bank_switch = intel_pre_bank_switch,
382         .post_bank_switch = intel_post_bank_switch,
383
384         .sync_arm = intel_sync_arm,
385         .sync_go_unlocked = intel_sync_go_unlocked,
386         .sync_go = intel_sync_go,
387         .sync_check_cmdsync_unlocked = intel_check_cmdsync_unlocked,
388
389         .program_sdi = intel_program_sdi,
390 };
391 EXPORT_SYMBOL_NS(sdw_intel_lnl_hw_ops, SOUNDWIRE_INTEL);
392
393 MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK);