]> Git Repo - J-linux.git/blob - drivers/soundwire/intel_ace2x.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / soundwire / intel_ace2x.c
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 // Copyright(c) 2023 Intel Corporation
3
4 /*
5  * Soundwire Intel ops for LunarLake
6  */
7
8 #include <linux/acpi.h>
9 #include <linux/cleanup.h>
10 #include <linux/device.h>
11 #include <linux/soundwire/sdw_registers.h>
12 #include <linux/soundwire/sdw.h>
13 #include <linux/soundwire/sdw_intel.h>
14 #include <sound/hdaudio.h>
15 #include <sound/hda-mlink.h>
16 #include <sound/hda_register.h>
17 #include <sound/pcm_params.h>
18 #include "cadence_master.h"
19 #include "bus.h"
20 #include "intel.h"
21
22 /*
23  * shim vendor-specific (vs) ops
24  */
25
26 static void intel_shim_vs_init(struct sdw_intel *sdw)
27 {
28         void __iomem *shim_vs = sdw->link_res->shim_vs;
29         struct sdw_bus *bus = &sdw->cdns.bus;
30         struct sdw_intel_prop *intel_prop;
31         u16 clde;
32         u16 doaise2;
33         u16 dodse2;
34         u16 clds;
35         u16 clss;
36         u16 doaise;
37         u16 doais;
38         u16 dodse;
39         u16 dods;
40         u16 act;
41
42         intel_prop = bus->vendor_specific_prop;
43         clde = intel_prop->clde;
44         doaise2 = intel_prop->doaise2;
45         dodse2 = intel_prop->dodse2;
46         clds = intel_prop->clds;
47         clss = intel_prop->clss;
48         doaise = intel_prop->doaise;
49         doais = intel_prop->doais;
50         dodse = intel_prop->dodse;
51         dods = intel_prop->dods;
52
53         act = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_ACTMCTL);
54         u16p_replace_bits(&act, clde, SDW_SHIM3_INTEL_VS_ACTMCTL_CLDE);
55         u16p_replace_bits(&act, doaise2, SDW_SHIM3_INTEL_VS_ACTMCTL_DOAISE2);
56         u16p_replace_bits(&act, dodse2, SDW_SHIM3_INTEL_VS_ACTMCTL_DODSE2);
57         u16p_replace_bits(&act, clds, SDW_SHIM3_INTEL_VS_ACTMCTL_CLDS);
58         u16p_replace_bits(&act, clss, SDW_SHIM3_INTEL_VS_ACTMCTL_CLSS);
59         u16p_replace_bits(&act, doaise, SDW_SHIM2_INTEL_VS_ACTMCTL_DOAISE);
60         u16p_replace_bits(&act, doais, SDW_SHIM2_INTEL_VS_ACTMCTL_DOAIS);
61         u16p_replace_bits(&act, dodse, SDW_SHIM2_INTEL_VS_ACTMCTL_DODSE);
62         u16p_replace_bits(&act, dods, SDW_SHIM2_INTEL_VS_ACTMCTL_DODS);
63         act |= SDW_SHIM2_INTEL_VS_ACTMCTL_DACTQE;
64         intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_ACTMCTL, act);
65         usleep_range(10, 15);
66 }
67
68 static void intel_shim_vs_set_clock_source(struct sdw_intel *sdw, u32 source)
69 {
70         void __iomem *shim_vs = sdw->link_res->shim_vs;
71         u32 val;
72
73         val = intel_readl(shim_vs, SDW_SHIM2_INTEL_VS_LVSCTL);
74
75         u32p_replace_bits(&val, source, SDW_SHIM2_INTEL_VS_LVSCTL_MLCS);
76
77         intel_writel(shim_vs, SDW_SHIM2_INTEL_VS_LVSCTL, val);
78
79         dev_dbg(sdw->cdns.dev, "clock source %d LVSCTL %#x\n", source, val);
80 }
81
82 static int intel_shim_check_wake(struct sdw_intel *sdw)
83 {
84         /*
85          * We follow the HDaudio example and resume unconditionally
86          * without checking the WAKESTS bit for that specific link
87          */
88
89         return 1;
90 }
91
92 static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
93 {
94         u16 lsdiid = 0;
95         u16 wake_en;
96         u16 wake_sts;
97         int ret;
98
99         mutex_lock(sdw->link_res->shim_lock);
100
101         ret = hdac_bus_eml_sdw_get_lsdiid_unlocked(sdw->link_res->hbus, sdw->instance, &lsdiid);
102         if (ret < 0)
103                 goto unlock;
104
105         wake_en = snd_hdac_chip_readw(sdw->link_res->hbus, WAKEEN);
106
107         if (wake_enable) {
108                 /* Enable the wakeup */
109                 wake_en |= lsdiid;
110
111                 snd_hdac_chip_writew(sdw->link_res->hbus, WAKEEN, wake_en);
112         } else {
113                 /* Disable the wake up interrupt */
114                 wake_en &= ~lsdiid;
115                 snd_hdac_chip_writew(sdw->link_res->hbus, WAKEEN, wake_en);
116
117                 /* Clear wake status (W1C) */
118                 wake_sts = snd_hdac_chip_readw(sdw->link_res->hbus, STATESTS);
119                 wake_sts |= lsdiid;
120                 snd_hdac_chip_writew(sdw->link_res->hbus, STATESTS, wake_sts);
121         }
122 unlock:
123         mutex_unlock(sdw->link_res->shim_lock);
124 }
125
126 static int intel_link_power_up(struct sdw_intel *sdw)
127 {
128         struct sdw_bus *bus = &sdw->cdns.bus;
129         struct sdw_master_prop *prop = &bus->prop;
130         u32 *shim_mask = sdw->link_res->shim_mask;
131         unsigned int link_id = sdw->instance;
132         u32 clock_source;
133         u32 syncprd;
134         int ret;
135
136         if (prop->mclk_freq % 6000000) {
137                 if (prop->mclk_freq % 2400000) {
138                         syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24_576;
139                         clock_source = SDW_SHIM2_MLCS_CARDINAL_CLK;
140                 } else {
141                         syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
142                         clock_source = SDW_SHIM2_MLCS_XTAL_CLK;
143                 }
144         } else {
145                 syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_96;
146                 clock_source = SDW_SHIM2_MLCS_AUDIO_PLL_CLK;
147         }
148
149         mutex_lock(sdw->link_res->shim_lock);
150
151         ret = hdac_bus_eml_sdw_power_up_unlocked(sdw->link_res->hbus, link_id);
152         if (ret < 0) {
153                 dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_up failed: %d\n",
154                         __func__, ret);
155                 goto out;
156         }
157
158         intel_shim_vs_set_clock_source(sdw, clock_source);
159
160         if (!*shim_mask) {
161                 /* we first need to program the SyncPRD/CPU registers */
162                 dev_dbg(sdw->cdns.dev, "first link up, programming SYNCPRD\n");
163
164                 ret =  hdac_bus_eml_sdw_set_syncprd_unlocked(sdw->link_res->hbus, syncprd);
165                 if (ret < 0) {
166                         dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_set_syncprd failed: %d\n",
167                                 __func__, ret);
168                         goto out;
169                 }
170
171                 /* SYNCPU will change once link is active */
172                 ret =  hdac_bus_eml_sdw_wait_syncpu_unlocked(sdw->link_res->hbus);
173                 if (ret < 0) {
174                         dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_wait_syncpu failed: %d\n",
175                                 __func__, ret);
176                         goto out;
177                 }
178
179                 hdac_bus_eml_enable_interrupt_unlocked(sdw->link_res->hbus, true,
180                                                        AZX_REG_ML_LEPTR_ID_SDW, true);
181         }
182
183         *shim_mask |= BIT(link_id);
184
185         sdw->cdns.link_up = true;
186
187         intel_shim_vs_init(sdw);
188
189 out:
190         mutex_unlock(sdw->link_res->shim_lock);
191
192         return ret;
193 }
194
195 static int intel_link_power_down(struct sdw_intel *sdw)
196 {
197         u32 *shim_mask = sdw->link_res->shim_mask;
198         unsigned int link_id = sdw->instance;
199         int ret;
200
201         mutex_lock(sdw->link_res->shim_lock);
202
203         sdw->cdns.link_up = false;
204
205         *shim_mask &= ~BIT(link_id);
206
207         if (!*shim_mask)
208                 hdac_bus_eml_enable_interrupt_unlocked(sdw->link_res->hbus, true,
209                                                        AZX_REG_ML_LEPTR_ID_SDW, false);
210
211         ret = hdac_bus_eml_sdw_power_down_unlocked(sdw->link_res->hbus, link_id);
212         if (ret < 0) {
213                 dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_down failed: %d\n",
214                         __func__, ret);
215
216                 /*
217                  * we leave the sdw->cdns.link_up flag as false since we've disabled
218                  * the link at this point and cannot handle interrupts any longer.
219                  */
220         }
221
222         mutex_unlock(sdw->link_res->shim_lock);
223
224         return ret;
225 }
226
227 static void intel_sync_arm(struct sdw_intel *sdw)
228 {
229         unsigned int link_id = sdw->instance;
230
231         mutex_lock(sdw->link_res->shim_lock);
232
233         hdac_bus_eml_sdw_sync_arm_unlocked(sdw->link_res->hbus, link_id);
234
235         mutex_unlock(sdw->link_res->shim_lock);
236 }
237
238 static int intel_sync_go_unlocked(struct sdw_intel *sdw)
239 {
240         int ret;
241
242         ret = hdac_bus_eml_sdw_sync_go_unlocked(sdw->link_res->hbus);
243         if (ret < 0)
244                 dev_err(sdw->cdns.dev, "%s: SyncGO clear failed: %d\n", __func__, ret);
245
246         return ret;
247 }
248
249 static int intel_sync_go(struct sdw_intel *sdw)
250 {
251         int ret;
252
253         mutex_lock(sdw->link_res->shim_lock);
254
255         ret = intel_sync_go_unlocked(sdw);
256
257         mutex_unlock(sdw->link_res->shim_lock);
258
259         return ret;
260 }
261
262 static bool intel_check_cmdsync_unlocked(struct sdw_intel *sdw)
263 {
264         return hdac_bus_eml_sdw_check_cmdsync_unlocked(sdw->link_res->hbus);
265 }
266
267 /* DAI callbacks */
268 static int intel_params_stream(struct sdw_intel *sdw,
269                                struct snd_pcm_substream *substream,
270                                struct snd_soc_dai *dai,
271                                struct snd_pcm_hw_params *hw_params,
272                                int link_id, int alh_stream_id)
273 {
274         struct sdw_intel_link_res *res = sdw->link_res;
275         struct sdw_intel_stream_params_data params_data;
276
277         params_data.substream = substream;
278         params_data.dai = dai;
279         params_data.hw_params = hw_params;
280         params_data.link_id = link_id;
281         params_data.alh_stream_id = alh_stream_id;
282
283         if (res->ops && res->ops->params_stream && res->dev)
284                 return res->ops->params_stream(res->dev,
285                                                &params_data);
286         return -EIO;
287 }
288
289 static int intel_free_stream(struct sdw_intel *sdw,
290                              struct snd_pcm_substream *substream,
291                              struct snd_soc_dai *dai,
292                              int link_id)
293
294 {
295         struct sdw_intel_link_res *res = sdw->link_res;
296         struct sdw_intel_stream_free_data free_data;
297
298         free_data.substream = substream;
299         free_data.dai = dai;
300         free_data.link_id = link_id;
301
302         if (res->ops && res->ops->free_stream && res->dev)
303                 return res->ops->free_stream(res->dev,
304                                              &free_data);
305
306         return 0;
307 }
308
309 /*
310  * DAI operations
311  */
312 static int intel_hw_params(struct snd_pcm_substream *substream,
313                            struct snd_pcm_hw_params *params,
314                            struct snd_soc_dai *dai)
315 {
316         struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
317         struct sdw_intel *sdw = cdns_to_intel(cdns);
318         struct sdw_cdns_dai_runtime *dai_runtime;
319         struct sdw_cdns_pdi *pdi;
320         struct sdw_stream_config sconfig;
321         int ch, dir;
322         int ret;
323
324         dai_runtime = cdns->dai_runtime_array[dai->id];
325         if (!dai_runtime)
326                 return -EIO;
327
328         ch = params_channels(params);
329         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
330                 dir = SDW_DATA_DIR_RX;
331         else
332                 dir = SDW_DATA_DIR_TX;
333
334         pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
335         if (!pdi)
336                 return -EINVAL;
337
338         /* use same definitions for alh_id as previous generations */
339         pdi->intel_alh_id = (sdw->instance * 16) + pdi->num + 3;
340         if (pdi->num >= 2)
341                 pdi->intel_alh_id += 2;
342
343         /* the SHIM will be configured in the callback functions */
344
345         sdw_cdns_config_stream(cdns, ch, dir, pdi);
346
347         /* store pdi and state, may be needed in prepare step */
348         dai_runtime->paused = false;
349         dai_runtime->suspended = false;
350         dai_runtime->pdi = pdi;
351
352         /* Inform DSP about PDI stream number */
353         ret = intel_params_stream(sdw, substream, dai, params,
354                                   sdw->instance,
355                                   pdi->intel_alh_id);
356         if (ret)
357                 return ret;
358
359         sconfig.direction = dir;
360         sconfig.ch_count = ch;
361         sconfig.frame_rate = params_rate(params);
362         sconfig.type = dai_runtime->stream_type;
363
364         sconfig.bps = snd_pcm_format_width(params_format(params));
365
366         /* Port configuration */
367         struct sdw_port_config *pconfig __free(kfree) = kzalloc(sizeof(*pconfig),
368                                                                 GFP_KERNEL);
369         if (!pconfig)
370                 return -ENOMEM;
371
372         pconfig->num = pdi->num;
373         pconfig->ch_mask = (1 << ch) - 1;
374
375         ret = sdw_stream_add_master(&cdns->bus, &sconfig,
376                                     pconfig, 1, dai_runtime->stream);
377         if (ret)
378                 dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
379
380         return ret;
381 }
382
383 static int intel_prepare(struct snd_pcm_substream *substream,
384                          struct snd_soc_dai *dai)
385 {
386         struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
387         struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
388         struct sdw_intel *sdw = cdns_to_intel(cdns);
389         struct sdw_cdns_dai_runtime *dai_runtime;
390         struct snd_pcm_hw_params *hw_params;
391         int ch, dir;
392
393         dai_runtime = cdns->dai_runtime_array[dai->id];
394         if (!dai_runtime) {
395                 dev_err(dai->dev, "failed to get dai runtime in %s\n",
396                         __func__);
397                 return -EIO;
398         }
399
400         hw_params = &rtd->dpcm[substream->stream].hw_params;
401         if (dai_runtime->suspended) {
402                 dai_runtime->suspended = false;
403
404                 /*
405                  * .prepare() is called after system resume, where we
406                  * need to reinitialize the SHIM/ALH/Cadence IP.
407                  * .prepare() is also called to deal with underflows,
408                  * but in those cases we cannot touch ALH/SHIM
409                  * registers
410                  */
411
412                 /* configure stream */
413                 ch = params_channels(hw_params);
414                 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
415                         dir = SDW_DATA_DIR_RX;
416                 else
417                         dir = SDW_DATA_DIR_TX;
418
419                 /* the SHIM will be configured in the callback functions */
420
421                 sdw_cdns_config_stream(cdns, ch, dir, dai_runtime->pdi);
422         }
423
424         /* Inform DSP about PDI stream number */
425         return intel_params_stream(sdw, substream, dai, hw_params, sdw->instance,
426                                    dai_runtime->pdi->intel_alh_id);
427 }
428
429 static int
430 intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
431 {
432         struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
433         struct sdw_intel *sdw = cdns_to_intel(cdns);
434         struct sdw_cdns_dai_runtime *dai_runtime;
435         int ret;
436
437         dai_runtime = cdns->dai_runtime_array[dai->id];
438         if (!dai_runtime)
439                 return -EIO;
440
441         /*
442          * The sdw stream state will transition to RELEASED when stream->
443          * master_list is empty. So the stream state will transition to
444          * DEPREPARED for the first cpu-dai and to RELEASED for the last
445          * cpu-dai.
446          */
447         ret = sdw_stream_remove_master(&cdns->bus, dai_runtime->stream);
448         if (ret < 0) {
449                 dev_err(dai->dev, "remove master from stream %s failed: %d\n",
450                         dai_runtime->stream->name, ret);
451                 return ret;
452         }
453
454         ret = intel_free_stream(sdw, substream, dai, sdw->instance);
455         if (ret < 0) {
456                 dev_err(dai->dev, "intel_free_stream: failed %d\n", ret);
457                 return ret;
458         }
459
460         dai_runtime->pdi = NULL;
461
462         return 0;
463 }
464
465 static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,
466                                     void *stream, int direction)
467 {
468         return cdns_set_sdw_stream(dai, stream, direction);
469 }
470
471 static void *intel_get_sdw_stream(struct snd_soc_dai *dai,
472                                   int direction)
473 {
474         struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
475         struct sdw_cdns_dai_runtime *dai_runtime;
476
477         dai_runtime = cdns->dai_runtime_array[dai->id];
478         if (!dai_runtime)
479                 return ERR_PTR(-EINVAL);
480
481         return dai_runtime->stream;
482 }
483
484 static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
485 {
486         struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
487         struct sdw_intel *sdw = cdns_to_intel(cdns);
488         struct sdw_intel_link_res *res = sdw->link_res;
489         struct sdw_cdns_dai_runtime *dai_runtime;
490         int ret = 0;
491
492         /*
493          * The .trigger callback is used to program HDaudio DMA and send required IPC to audio
494          * firmware.
495          */
496         if (res->ops && res->ops->trigger) {
497                 ret = res->ops->trigger(substream, cmd, dai);
498                 if (ret < 0)
499                         return ret;
500         }
501
502         dai_runtime = cdns->dai_runtime_array[dai->id];
503         if (!dai_runtime) {
504                 dev_err(dai->dev, "failed to get dai runtime in %s\n",
505                         __func__);
506                 return -EIO;
507         }
508
509         switch (cmd) {
510         case SNDRV_PCM_TRIGGER_SUSPEND:
511
512                 /*
513                  * The .prepare callback is used to deal with xruns and resume operations.
514                  * In the case of xruns, the DMAs and SHIM registers cannot be touched,
515                  * but for resume operations the DMAs and SHIM registers need to be initialized.
516                  * the .trigger callback is used to track the suspend case only.
517                  */
518
519                 dai_runtime->suspended = true;
520
521                 break;
522
523         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
524                 dai_runtime->paused = true;
525                 break;
526         case SNDRV_PCM_TRIGGER_STOP:
527         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
528                 dai_runtime->paused = false;
529                 break;
530         default:
531                 break;
532         }
533
534         return ret;
535 }
536
537 static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
538         .hw_params = intel_hw_params,
539         .prepare = intel_prepare,
540         .hw_free = intel_hw_free,
541         .trigger = intel_trigger,
542         .set_stream = intel_pcm_set_sdw_stream,
543         .get_stream = intel_get_sdw_stream,
544 };
545
546 static const struct snd_soc_component_driver dai_component = {
547         .name                   = "soundwire",
548 };
549
550 /*
551  * PDI routines
552  */
553 static void intel_pdi_init(struct sdw_intel *sdw,
554                            struct sdw_cdns_stream_config *config)
555 {
556         void __iomem *shim = sdw->link_res->shim;
557         int pcm_cap;
558
559         /* PCM Stream Capability */
560         pcm_cap = intel_readw(shim, SDW_SHIM2_PCMSCAP);
561
562         config->pcm_bd = FIELD_GET(SDW_SHIM2_PCMSCAP_BSS, pcm_cap);
563         config->pcm_in = FIELD_GET(SDW_SHIM2_PCMSCAP_ISS, pcm_cap);
564         config->pcm_out = FIELD_GET(SDW_SHIM2_PCMSCAP_ISS, pcm_cap);
565
566         dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n",
567                 config->pcm_bd, config->pcm_in, config->pcm_out);
568 }
569
570 static int
571 intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num)
572 {
573         void __iomem *shim = sdw->link_res->shim;
574
575         /* zero based values for channel count in register */
576         return intel_readw(shim, SDW_SHIM2_PCMSYCHC(pdi_num)) + 1;
577 }
578
579 static void intel_pdi_get_ch_update(struct sdw_intel *sdw,
580                                     struct sdw_cdns_pdi *pdi,
581                                     unsigned int num_pdi,
582                                     unsigned int *num_ch)
583 {
584         int ch_count = 0;
585         int i;
586
587         for (i = 0; i < num_pdi; i++) {
588                 pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num);
589                 ch_count += pdi->ch_count;
590                 pdi++;
591         }
592
593         *num_ch = ch_count;
594 }
595
596 static void intel_pdi_stream_ch_update(struct sdw_intel *sdw,
597                                        struct sdw_cdns_streams *stream)
598 {
599         intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd,
600                                 &stream->num_ch_bd);
601
602         intel_pdi_get_ch_update(sdw, stream->in, stream->num_in,
603                                 &stream->num_ch_in);
604
605         intel_pdi_get_ch_update(sdw, stream->out, stream->num_out,
606                                 &stream->num_ch_out);
607 }
608
609 static int intel_create_dai(struct sdw_cdns *cdns,
610                             struct snd_soc_dai_driver *dais,
611                             enum intel_pdi_type type,
612                             u32 num, u32 off, u32 max_ch)
613 {
614         int i;
615
616         if (!num)
617                 return 0;
618
619         for (i = off; i < (off + num); i++) {
620                 dais[i].name = devm_kasprintf(cdns->dev, GFP_KERNEL,
621                                               "SDW%d Pin%d",
622                                               cdns->instance, i);
623                 if (!dais[i].name)
624                         return -ENOMEM;
625
626                 if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) {
627                         dais[i].playback.channels_min = 1;
628                         dais[i].playback.channels_max = max_ch;
629                 }
630
631                 if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) {
632                         dais[i].capture.channels_min = 1;
633                         dais[i].capture.channels_max = max_ch;
634                 }
635
636                 dais[i].ops = &intel_pcm_dai_ops;
637         }
638
639         return 0;
640 }
641
642 static int intel_register_dai(struct sdw_intel *sdw)
643 {
644         struct sdw_cdns_dai_runtime **dai_runtime_array;
645         struct sdw_cdns_stream_config config;
646         struct sdw_cdns *cdns = &sdw->cdns;
647         struct sdw_cdns_streams *stream;
648         struct snd_soc_dai_driver *dais;
649         int num_dai;
650         int ret;
651         int off = 0;
652
653         /* Read the PDI config and initialize cadence PDI */
654         intel_pdi_init(sdw, &config);
655         ret = sdw_cdns_pdi_init(cdns, config);
656         if (ret)
657                 return ret;
658
659         intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm);
660
661         /* DAIs are created based on total number of PDIs supported */
662         num_dai = cdns->pcm.num_pdi;
663
664         dai_runtime_array = devm_kcalloc(cdns->dev, num_dai,
665                                          sizeof(struct sdw_cdns_dai_runtime *),
666                                          GFP_KERNEL);
667         if (!dai_runtime_array)
668                 return -ENOMEM;
669         cdns->dai_runtime_array = dai_runtime_array;
670
671         dais = devm_kcalloc(cdns->dev, num_dai, sizeof(*dais), GFP_KERNEL);
672         if (!dais)
673                 return -ENOMEM;
674
675         /* Create PCM DAIs */
676         stream = &cdns->pcm;
677
678         ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pcm.num_in,
679                                off, stream->num_ch_in);
680         if (ret)
681                 return ret;
682
683         off += cdns->pcm.num_in;
684         ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pcm.num_out,
685                                off, stream->num_ch_out);
686         if (ret)
687                 return ret;
688
689         off += cdns->pcm.num_out;
690         ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pcm.num_bd,
691                                off, stream->num_ch_bd);
692         if (ret)
693                 return ret;
694
695         return devm_snd_soc_register_component(cdns->dev, &dai_component,
696                                                dais, num_dai);
697 }
698
699 static void intel_program_sdi(struct sdw_intel *sdw, int dev_num)
700 {
701         int ret;
702
703         ret = hdac_bus_eml_sdw_set_lsdiid(sdw->link_res->hbus, sdw->instance, dev_num);
704         if (ret < 0)
705                 dev_err(sdw->cdns.dev, "%s: could not set lsdiid for link %d %d\n",
706                         __func__, sdw->instance, dev_num);
707 }
708
709 static int intel_get_link_count(struct sdw_intel *sdw)
710 {
711         int ret;
712
713         ret = hdac_bus_eml_get_count(sdw->link_res->hbus, true, AZX_REG_ML_LEPTR_ID_SDW);
714         if (!ret) {
715                 dev_err(sdw->cdns.dev, "%s: could not retrieve link count\n", __func__);
716                 return -ENODEV;
717         }
718
719         if (ret > SDW_INTEL_MAX_LINKS) {
720                 dev_err(sdw->cdns.dev, "%s: link count %d exceed max %d\n", __func__, ret, SDW_INTEL_MAX_LINKS);
721                 return -EINVAL;
722         }
723
724         return ret;
725 }
726
727 const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops = {
728         .debugfs_init = intel_ace2x_debugfs_init,
729         .debugfs_exit = intel_ace2x_debugfs_exit,
730
731         .get_link_count = intel_get_link_count,
732
733         .register_dai = intel_register_dai,
734
735         .check_clock_stop = intel_check_clock_stop,
736         .start_bus = intel_start_bus,
737         .start_bus_after_reset = intel_start_bus_after_reset,
738         .start_bus_after_clock_stop = intel_start_bus_after_clock_stop,
739         .stop_bus = intel_stop_bus,
740
741         .link_power_up = intel_link_power_up,
742         .link_power_down = intel_link_power_down,
743
744         .shim_check_wake = intel_shim_check_wake,
745         .shim_wake = intel_shim_wake,
746
747         .pre_bank_switch = intel_pre_bank_switch,
748         .post_bank_switch = intel_post_bank_switch,
749
750         .sync_arm = intel_sync_arm,
751         .sync_go_unlocked = intel_sync_go_unlocked,
752         .sync_go = intel_sync_go,
753         .sync_check_cmdsync_unlocked = intel_check_cmdsync_unlocked,
754
755         .program_sdi = intel_program_sdi,
756 };
757 EXPORT_SYMBOL_NS(sdw_intel_lnl_hw_ops, "SOUNDWIRE_INTEL");
758
759 MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
This page took 0.06877 seconds and 4 git commands to generate.