]> Git Repo - linux.git/blob - sound/soc/amd/acp/acp-i2s.c
Linux 6.14-rc3
[linux.git] / sound / soc / amd / acp / acp-i2s.c
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
3 // This file is provided under a dual BSD/GPLv2 license. When using or
4 // redistributing this file, you may do so under either license.
5 //
6 // Copyright(c) 2021 Advanced Micro Devices, Inc.
7 //
8 // Authors: Ajit Kumar Pandey <[email protected]>
9 //
10
11 /*
12  * Generic Hardware interface for ACP Audio I2S controller
13  */
14
15 #include <linux/platform_device.h>
16 #include <linux/module.h>
17 #include <linux/err.h>
18 #include <linux/io.h>
19 #include <sound/pcm_params.h>
20 #include <sound/soc.h>
21 #include <sound/soc-dai.h>
22 #include <linux/dma-mapping.h>
23 #include <linux/bitfield.h>
24
25 #include "amd.h"
26
27 #define DRV_NAME "acp_i2s_playcap"
28 #define I2S_MASTER_MODE_ENABLE          1
29 #define LRCLK_DIV_FIELD                 GENMASK(10, 2)
30 #define BCLK_DIV_FIELD                  GENMASK(23, 11)
31 #define ACP63_LRCLK_DIV_FIELD           GENMASK(12, 2)
32 #define ACP63_BCLK_DIV_FIELD            GENMASK(23, 13)
33
34 static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id)
35 {
36         u32 i2s_clk_reg, val;
37         struct acp_chip_info *chip;
38         struct device *dev;
39
40         dev = adata->dev;
41         chip = dev_get_platdata(dev);
42         switch (dai_id) {
43         case I2S_SP_INSTANCE:
44                 i2s_clk_reg = ACP_I2STDM0_MSTRCLKGEN;
45                 break;
46         case I2S_BT_INSTANCE:
47                 i2s_clk_reg = ACP_I2STDM1_MSTRCLKGEN;
48                 break;
49         case I2S_HS_INSTANCE:
50                 i2s_clk_reg = ACP_I2STDM2_MSTRCLKGEN;
51                 break;
52         default:
53                 i2s_clk_reg = ACP_I2STDM0_MSTRCLKGEN;
54                 break;
55         }
56
57         val  = I2S_MASTER_MODE_ENABLE;
58         if (adata->tdm_mode)
59                 val |= BIT(1);
60
61         switch (chip->acp_rev) {
62         case ACP63_PCI_ID:
63         case ACP70_PCI_ID:
64         case ACP71_PCI_ID:
65                 val |= FIELD_PREP(ACP63_LRCLK_DIV_FIELD, adata->lrclk_div);
66                 val |= FIELD_PREP(ACP63_BCLK_DIV_FIELD, adata->bclk_div);
67                 break;
68         default:
69                 val |= FIELD_PREP(LRCLK_DIV_FIELD, adata->lrclk_div);
70                 val |= FIELD_PREP(BCLK_DIV_FIELD, adata->bclk_div);
71         }
72         writel(val, adata->acp_base + i2s_clk_reg);
73 }
74
75 static int acp_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
76                            unsigned int fmt)
77 {
78         struct acp_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai);
79         int mode;
80
81         mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
82         switch (mode) {
83         case SND_SOC_DAIFMT_I2S:
84                 adata->tdm_mode = TDM_DISABLE;
85                 break;
86         case SND_SOC_DAIFMT_DSP_A:
87                 adata->tdm_mode = TDM_ENABLE;
88                 break;
89         default:
90                 return -EINVAL;
91         }
92         return 0;
93 }
94
95 static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mask,
96                                 int slots, int slot_width)
97 {
98         struct device *dev = dai->component->dev;
99         struct acp_dev_data *adata = snd_soc_dai_get_drvdata(dai);
100         struct acp_chip_info *chip;
101         struct acp_stream *stream;
102         int slot_len, no_of_slots;
103
104         chip = dev_get_platdata(dev);
105         switch (slot_width) {
106         case SLOT_WIDTH_8:
107                 slot_len = 8;
108                 break;
109         case SLOT_WIDTH_16:
110                 slot_len = 16;
111                 break;
112         case SLOT_WIDTH_24:
113                 slot_len = 24;
114                 break;
115         case SLOT_WIDTH_32:
116                 slot_len = 0;
117                 break;
118         default:
119                 dev_err(dev, "Unsupported bitdepth %d\n", slot_width);
120                 return -EINVAL;
121         }
122
123         switch (chip->acp_rev) {
124         case ACP_RN_PCI_ID:
125         case ACP_RMB_PCI_ID:
126                 switch (slots) {
127                 case 1 ... 7:
128                         no_of_slots = slots;
129                         break;
130                 case 8:
131                         no_of_slots = 0;
132                         break;
133                 default:
134                         dev_err(dev, "Unsupported slots %d\n", slots);
135                         return -EINVAL;
136                 }
137                 break;
138         case ACP63_PCI_ID:
139         case ACP70_PCI_ID:
140         case ACP71_PCI_ID:
141                 switch (slots) {
142                 case 1 ... 31:
143                         no_of_slots = slots;
144                         break;
145                 case 32:
146                         no_of_slots = 0;
147                         break;
148                 default:
149                         dev_err(dev, "Unsupported slots %d\n", slots);
150                         return -EINVAL;
151                 }
152                 break;
153         default:
154                 dev_err(dev, "Unknown chip revision %d\n", chip->acp_rev);
155                 return -EINVAL;
156         }
157
158         slots = no_of_slots;
159
160         spin_lock_irq(&adata->acp_lock);
161         list_for_each_entry(stream, &adata->stream_list, list) {
162                 switch (chip->acp_rev) {
163                 case ACP_RN_PCI_ID:
164                 case ACP_RMB_PCI_ID:
165                         if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
166                                 adata->tdm_tx_fmt[stream->dai_id - 1] =
167                                         FRM_LEN | (slots << 15) | (slot_len << 18);
168                         else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)
169                                 adata->tdm_rx_fmt[stream->dai_id - 1] =
170                                         FRM_LEN | (slots << 15) | (slot_len << 18);
171                         break;
172                 case ACP63_PCI_ID:
173                 case ACP70_PCI_ID:
174                 case ACP71_PCI_ID:
175                         if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
176                                 adata->tdm_tx_fmt[stream->dai_id - 1] =
177                                                 FRM_LEN | (slots << 13) | (slot_len << 18);
178                         else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)
179                                 adata->tdm_rx_fmt[stream->dai_id - 1] =
180                                                 FRM_LEN | (slots << 13) | (slot_len << 18);
181                         break;
182                 default:
183                         dev_err(dev, "Unknown chip revision %d\n", chip->acp_rev);
184                         spin_unlock_irq(&adata->acp_lock);
185                         return -EINVAL;
186                 }
187         }
188         spin_unlock_irq(&adata->acp_lock);
189         return 0;
190 }
191
192 static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
193                             struct snd_soc_dai *dai)
194 {
195         struct device *dev = dai->component->dev;
196         struct acp_dev_data *adata;
197         struct acp_resource *rsrc;
198         u32 val;
199         u32 xfer_resolution;
200         u32 reg_val, fmt_reg, tdm_fmt;
201         u32 lrclk_div_val, bclk_div_val;
202
203         adata = snd_soc_dai_get_drvdata(dai);
204         rsrc = adata->rsrc;
205
206         /* These values are as per Hardware Spec */
207         switch (params_format(params)) {
208         case SNDRV_PCM_FORMAT_U8:
209         case SNDRV_PCM_FORMAT_S8:
210                 xfer_resolution = 0x0;
211                 break;
212         case SNDRV_PCM_FORMAT_S16_LE:
213                 xfer_resolution = 0x02;
214                 break;
215         case SNDRV_PCM_FORMAT_S24_LE:
216                 xfer_resolution = 0x04;
217                 break;
218         case SNDRV_PCM_FORMAT_S32_LE:
219                 xfer_resolution = 0x05;
220                 break;
221         default:
222                 return -EINVAL;
223         }
224
225         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
226                 switch (dai->driver->id) {
227                 case I2S_BT_INSTANCE:
228                         reg_val = ACP_BTTDM_ITER;
229                         fmt_reg = ACP_BTTDM_TXFRMT;
230                         break;
231                 case I2S_SP_INSTANCE:
232                         reg_val = ACP_I2STDM_ITER;
233                         fmt_reg = ACP_I2STDM_TXFRMT;
234                         break;
235                 case I2S_HS_INSTANCE:
236                         reg_val = ACP_HSTDM_ITER;
237                         fmt_reg = ACP_HSTDM_TXFRMT;
238                         break;
239                 default:
240                         dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
241                         return -EINVAL;
242                 }
243                 adata->xfer_tx_resolution[dai->driver->id - 1] = xfer_resolution;
244         } else {
245                 switch (dai->driver->id) {
246                 case I2S_BT_INSTANCE:
247                         reg_val = ACP_BTTDM_IRER;
248                         fmt_reg = ACP_BTTDM_RXFRMT;
249                         break;
250                 case I2S_SP_INSTANCE:
251                         reg_val = ACP_I2STDM_IRER;
252                         fmt_reg = ACP_I2STDM_RXFRMT;
253                         break;
254                 case I2S_HS_INSTANCE:
255                         reg_val = ACP_HSTDM_IRER;
256                         fmt_reg = ACP_HSTDM_RXFRMT;
257                         break;
258                 default:
259                         dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
260                         return -EINVAL;
261                 }
262                 adata->xfer_rx_resolution[dai->driver->id - 1] = xfer_resolution;
263         }
264
265         val = readl(adata->acp_base + reg_val);
266         val &= ~ACP3x_ITER_IRER_SAMP_LEN_MASK;
267         val = val | (xfer_resolution  << 3);
268         writel(val, adata->acp_base + reg_val);
269
270         if (adata->tdm_mode) {
271                 val = readl(adata->acp_base + reg_val);
272                 writel(val | BIT(1), adata->acp_base + reg_val);
273                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
274                         tdm_fmt = adata->tdm_tx_fmt[dai->driver->id - 1];
275                 else
276                         tdm_fmt = adata->tdm_rx_fmt[dai->driver->id - 1];
277                 writel(tdm_fmt, adata->acp_base + fmt_reg);
278         }
279
280         if (rsrc->soc_mclk) {
281                 switch (params_format(params)) {
282                 case SNDRV_PCM_FORMAT_S16_LE:
283                         switch (params_rate(params)) {
284                         case 8000:
285                                 bclk_div_val = 768;
286                                 break;
287                         case 16000:
288                                 bclk_div_val = 384;
289                                 break;
290                         case 24000:
291                                 bclk_div_val = 256;
292                                 break;
293                         case 32000:
294                                 bclk_div_val = 192;
295                                 break;
296                         case 44100:
297                         case 48000:
298                                 bclk_div_val = 128;
299                                 break;
300                         case 88200:
301                         case 96000:
302                                 bclk_div_val = 64;
303                                 break;
304                         case 192000:
305                                 bclk_div_val = 32;
306                                 break;
307                         default:
308                                 return -EINVAL;
309                         }
310                         lrclk_div_val = 32;
311                         break;
312                 case SNDRV_PCM_FORMAT_S32_LE:
313                         switch (params_rate(params)) {
314                         case 8000:
315                                 bclk_div_val = 384;
316                                 break;
317                         case 16000:
318                                 bclk_div_val = 192;
319                                 break;
320                         case 24000:
321                                 bclk_div_val = 128;
322                                 break;
323                         case 32000:
324                                 bclk_div_val = 96;
325                                 break;
326                         case 44100:
327                         case 48000:
328                                 bclk_div_val = 64;
329                                 break;
330                         case 88200:
331                         case 96000:
332                                 bclk_div_val = 32;
333                                 break;
334                         case 192000:
335                                 bclk_div_val = 16;
336                                 break;
337                         default:
338                                 return -EINVAL;
339                         }
340                         lrclk_div_val = 64;
341                         break;
342                 default:
343                         return -EINVAL;
344                 }
345
346                 switch (params_rate(params)) {
347                 case 8000:
348                 case 16000:
349                 case 24000:
350                 case 48000:
351                 case 96000:
352                 case 192000:
353                         switch (params_channels(params)) {
354                         case 2:
355                                 break;
356                         case 4:
357                                 bclk_div_val = bclk_div_val >> 1;
358                                 lrclk_div_val = lrclk_div_val << 1;
359                                 break;
360                         case 8:
361                                 bclk_div_val = bclk_div_val >> 2;
362                                 lrclk_div_val = lrclk_div_val << 2;
363                                 break;
364                         case 16:
365                                 bclk_div_val = bclk_div_val >> 3;
366                                 lrclk_div_val = lrclk_div_val << 3;
367                                 break;
368                         case 32:
369                                 bclk_div_val = bclk_div_val >> 4;
370                                 lrclk_div_val = lrclk_div_val << 4;
371                                 break;
372                         default:
373                                 dev_err(dev, "Unsupported channels %#x\n",
374                                         params_channels(params));
375                         }
376                         break;
377                 default:
378                         break;
379                 }
380                 adata->lrclk_div = lrclk_div_val;
381                 adata->bclk_div = bclk_div_val;
382         }
383         return 0;
384 }
385
386 static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
387 {
388         struct acp_stream *stream = substream->runtime->private_data;
389         struct device *dev = dai->component->dev;
390         struct acp_dev_data *adata = dev_get_drvdata(dev);
391         struct acp_resource *rsrc = adata->rsrc;
392         u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg;
393
394         period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size);
395         buf_size = frames_to_bytes(substream->runtime, substream->runtime->buffer_size);
396
397         switch (cmd) {
398         case SNDRV_PCM_TRIGGER_START:
399         case SNDRV_PCM_TRIGGER_RESUME:
400         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
401                 stream->bytescount = acp_get_byte_count(adata, stream->dai_id, substream->stream);
402                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
403                         switch (dai->driver->id) {
404                         case I2S_BT_INSTANCE:
405                                 water_val = ACP_BT_TX_INTR_WATERMARK_SIZE(adata);
406                                 reg_val = ACP_BTTDM_ITER;
407                                 ier_val = ACP_BTTDM_IER;
408                                 buf_reg = ACP_BT_TX_RINGBUFSIZE(adata);
409                                 break;
410                         case I2S_SP_INSTANCE:
411                                 water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE(adata);
412                                 reg_val = ACP_I2STDM_ITER;
413                                 ier_val = ACP_I2STDM_IER;
414                                 buf_reg = ACP_I2S_TX_RINGBUFSIZE(adata);
415                                 break;
416                         case I2S_HS_INSTANCE:
417                                 water_val = ACP_HS_TX_INTR_WATERMARK_SIZE;
418                                 reg_val = ACP_HSTDM_ITER;
419                                 ier_val = ACP_HSTDM_IER;
420                                 buf_reg = ACP_HS_TX_RINGBUFSIZE;
421                                 break;
422                         default:
423                                 dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
424                                 return -EINVAL;
425                         }
426                 } else {
427                         switch (dai->driver->id) {
428                         case I2S_BT_INSTANCE:
429                                 water_val = ACP_BT_RX_INTR_WATERMARK_SIZE(adata);
430                                 reg_val = ACP_BTTDM_IRER;
431                                 ier_val = ACP_BTTDM_IER;
432                                 buf_reg = ACP_BT_RX_RINGBUFSIZE(adata);
433                                 break;
434                         case I2S_SP_INSTANCE:
435                                 water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE(adata);
436                                 reg_val = ACP_I2STDM_IRER;
437                                 ier_val = ACP_I2STDM_IER;
438                                 buf_reg = ACP_I2S_RX_RINGBUFSIZE(adata);
439                                 break;
440                         case I2S_HS_INSTANCE:
441                                 water_val = ACP_HS_RX_INTR_WATERMARK_SIZE;
442                                 reg_val = ACP_HSTDM_IRER;
443                                 ier_val = ACP_HSTDM_IER;
444                                 buf_reg = ACP_HS_RX_RINGBUFSIZE;
445                                 break;
446                         default:
447                                 dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
448                                 return -EINVAL;
449                         }
450                 }
451
452                 writel(period_bytes, adata->acp_base + water_val);
453                 writel(buf_size, adata->acp_base + buf_reg);
454                 if (rsrc->soc_mclk)
455                         acp_set_i2s_clk(adata, dai->driver->id);
456                 val = readl(adata->acp_base + reg_val);
457                 val = val | BIT(0);
458                 writel(val, adata->acp_base + reg_val);
459                 writel(1, adata->acp_base + ier_val);
460                 return 0;
461         case SNDRV_PCM_TRIGGER_STOP:
462         case SNDRV_PCM_TRIGGER_SUSPEND:
463         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
464                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
465                         switch (dai->driver->id) {
466                         case I2S_BT_INSTANCE:
467                                 reg_val = ACP_BTTDM_ITER;
468                                 break;
469                         case I2S_SP_INSTANCE:
470                                 reg_val = ACP_I2STDM_ITER;
471                                 break;
472                         case I2S_HS_INSTANCE:
473                                 reg_val = ACP_HSTDM_ITER;
474                                 break;
475                         default:
476                                 dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
477                                 return -EINVAL;
478                         }
479
480                 } else {
481                         switch (dai->driver->id) {
482                         case I2S_BT_INSTANCE:
483                                 reg_val = ACP_BTTDM_IRER;
484                                 break;
485                         case I2S_SP_INSTANCE:
486                                 reg_val = ACP_I2STDM_IRER;
487                                 break;
488                         case I2S_HS_INSTANCE:
489                                 reg_val = ACP_HSTDM_IRER;
490                                 break;
491                         default:
492                                 dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
493                                 return -EINVAL;
494                         }
495                 }
496                 val = readl(adata->acp_base + reg_val);
497                 val = val & ~BIT(0);
498                 writel(val, adata->acp_base + reg_val);
499
500                 if (!(readl(adata->acp_base + ACP_BTTDM_ITER) & BIT(0)) &&
501                     !(readl(adata->acp_base + ACP_BTTDM_IRER) & BIT(0)))
502                         writel(0, adata->acp_base + ACP_BTTDM_IER);
503                 if (!(readl(adata->acp_base + ACP_I2STDM_ITER) & BIT(0)) &&
504                     !(readl(adata->acp_base + ACP_I2STDM_IRER) & BIT(0)))
505                         writel(0, adata->acp_base + ACP_I2STDM_IER);
506                 if (!(readl(adata->acp_base + ACP_HSTDM_ITER) & BIT(0)) &&
507                     !(readl(adata->acp_base + ACP_HSTDM_IRER) & BIT(0)))
508                         writel(0, adata->acp_base + ACP_HSTDM_IER);
509                 return 0;
510         default:
511                 return -EINVAL;
512         }
513
514         return 0;
515 }
516
517 static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
518 {
519         struct device *dev = dai->component->dev;
520         struct acp_dev_data *adata = dev_get_drvdata(dev);
521         struct acp_chip_info *chip;
522         struct acp_resource *rsrc = adata->rsrc;
523         struct acp_stream *stream = substream->runtime->private_data;
524         u32 reg_dma_size = 0, reg_fifo_size = 0, reg_fifo_addr = 0;
525         u32 phy_addr = 0, acp_fifo_addr = 0, ext_int_ctrl;
526         unsigned int dir = substream->stream;
527
528         chip = dev_get_platdata(dev);
529         switch (dai->driver->id) {
530         case I2S_SP_INSTANCE:
531                 if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
532                         reg_dma_size = ACP_I2S_TX_DMA_SIZE(adata);
533                         acp_fifo_addr = rsrc->sram_pte_offset +
534                                                 SP_PB_FIFO_ADDR_OFFSET;
535                         reg_fifo_addr = ACP_I2S_TX_FIFOADDR(adata);
536                         reg_fifo_size = ACP_I2S_TX_FIFOSIZE(adata);
537
538                         if (chip->acp_rev >= ACP70_PCI_ID)
539                                 phy_addr = ACP7x_I2S_SP_TX_MEM_WINDOW_START;
540                         else
541                                 phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
542                         writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR(adata));
543                 } else {
544                         reg_dma_size = ACP_I2S_RX_DMA_SIZE(adata);
545                         acp_fifo_addr = rsrc->sram_pte_offset +
546                                                 SP_CAPT_FIFO_ADDR_OFFSET;
547                         reg_fifo_addr = ACP_I2S_RX_FIFOADDR(adata);
548                         reg_fifo_size = ACP_I2S_RX_FIFOSIZE(adata);
549
550                         if (chip->acp_rev >= ACP70_PCI_ID)
551                                 phy_addr = ACP7x_I2S_SP_RX_MEM_WINDOW_START;
552                         else
553                                 phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
554                         writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR(adata));
555                 }
556                 break;
557         case I2S_BT_INSTANCE:
558                 if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
559                         reg_dma_size = ACP_BT_TX_DMA_SIZE(adata);
560                         acp_fifo_addr = rsrc->sram_pte_offset +
561                                                 BT_PB_FIFO_ADDR_OFFSET;
562                         reg_fifo_addr = ACP_BT_TX_FIFOADDR(adata);
563                         reg_fifo_size = ACP_BT_TX_FIFOSIZE(adata);
564
565                         if (chip->acp_rev >= ACP70_PCI_ID)
566                                 phy_addr = ACP7x_I2S_BT_TX_MEM_WINDOW_START;
567                         else
568                                 phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
569                         writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR(adata));
570                 } else {
571                         reg_dma_size = ACP_BT_RX_DMA_SIZE(adata);
572                         acp_fifo_addr = rsrc->sram_pte_offset +
573                                                 BT_CAPT_FIFO_ADDR_OFFSET;
574                         reg_fifo_addr = ACP_BT_RX_FIFOADDR(adata);
575                         reg_fifo_size = ACP_BT_RX_FIFOSIZE(adata);
576
577                         if (chip->acp_rev >= ACP70_PCI_ID)
578                                 phy_addr = ACP7x_I2S_BT_RX_MEM_WINDOW_START;
579                         else
580                                 phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
581                         writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR(adata));
582                 }
583                 break;
584         case I2S_HS_INSTANCE:
585                 if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
586                         reg_dma_size = ACP_HS_TX_DMA_SIZE;
587                         acp_fifo_addr = rsrc->sram_pte_offset +
588                                 HS_PB_FIFO_ADDR_OFFSET;
589                         reg_fifo_addr = ACP_HS_TX_FIFOADDR;
590                         reg_fifo_size = ACP_HS_TX_FIFOSIZE;
591
592                         if (chip->acp_rev >= ACP70_PCI_ID)
593                                 phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START;
594                         else
595                                 phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
596                         writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR);
597                 } else {
598                         reg_dma_size = ACP_HS_RX_DMA_SIZE;
599                         acp_fifo_addr = rsrc->sram_pte_offset +
600                                         HS_CAPT_FIFO_ADDR_OFFSET;
601                         reg_fifo_addr = ACP_HS_RX_FIFOADDR;
602                         reg_fifo_size = ACP_HS_RX_FIFOSIZE;
603
604                         if (chip->acp_rev >= ACP70_PCI_ID)
605                                 phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START;
606                         else
607                                 phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
608                         writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR);
609                 }
610                 break;
611         default:
612                 dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
613                 return -EINVAL;
614         }
615
616         writel(DMA_SIZE, adata->acp_base + reg_dma_size);
617         writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr);
618         writel(FIFO_SIZE, adata->acp_base + reg_fifo_size);
619
620         ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
621         ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) |
622                         BIT(BT_RX_THRESHOLD(rsrc->offset)) |
623                         BIT(I2S_TX_THRESHOLD(rsrc->offset)) |
624                         BIT(BT_TX_THRESHOLD(rsrc->offset)) |
625                         BIT(HS_RX_THRESHOLD(rsrc->offset)) |
626                         BIT(HS_TX_THRESHOLD(rsrc->offset));
627
628         writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
629
630         return 0;
631 }
632
633 static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
634 {
635         struct acp_stream *stream = substream->runtime->private_data;
636         struct device *dev = dai->component->dev;
637         struct acp_dev_data *adata = dev_get_drvdata(dev);
638         struct acp_resource *rsrc = adata->rsrc;
639         unsigned int dir = substream->stream;
640         unsigned int irq_bit = 0;
641
642         switch (dai->driver->id) {
643         case I2S_SP_INSTANCE:
644                 if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
645                         irq_bit = BIT(I2S_TX_THRESHOLD(rsrc->offset));
646                         stream->pte_offset = ACP_SRAM_SP_PB_PTE_OFFSET;
647                         stream->fifo_offset = SP_PB_FIFO_ADDR_OFFSET;
648                 } else {
649                         irq_bit = BIT(I2S_RX_THRESHOLD(rsrc->offset));
650                         stream->pte_offset = ACP_SRAM_SP_CP_PTE_OFFSET;
651                         stream->fifo_offset = SP_CAPT_FIFO_ADDR_OFFSET;
652                 }
653                 break;
654         case I2S_BT_INSTANCE:
655                 if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
656                         irq_bit = BIT(BT_TX_THRESHOLD(rsrc->offset));
657                         stream->pte_offset = ACP_SRAM_BT_PB_PTE_OFFSET;
658                         stream->fifo_offset = BT_PB_FIFO_ADDR_OFFSET;
659                 } else {
660                         irq_bit = BIT(BT_RX_THRESHOLD(rsrc->offset));
661                         stream->pte_offset = ACP_SRAM_BT_CP_PTE_OFFSET;
662                         stream->fifo_offset = BT_CAPT_FIFO_ADDR_OFFSET;
663                 }
664                 break;
665         case I2S_HS_INSTANCE:
666                 if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
667                         irq_bit = BIT(HS_TX_THRESHOLD(rsrc->offset));
668                         stream->pte_offset = ACP_SRAM_HS_PB_PTE_OFFSET;
669                         stream->fifo_offset = HS_PB_FIFO_ADDR_OFFSET;
670                 } else {
671                         irq_bit = BIT(HS_RX_THRESHOLD(rsrc->offset));
672                         stream->pte_offset = ACP_SRAM_HS_CP_PTE_OFFSET;
673                         stream->fifo_offset = HS_CAPT_FIFO_ADDR_OFFSET;
674                 }
675                 break;
676         default:
677                 dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
678                 return -EINVAL;
679         }
680
681         /* Save runtime dai configuration in stream */
682         stream->id = dai->driver->id + dir;
683         stream->dai_id = dai->driver->id;
684         stream->irq_bit = irq_bit;
685         stream->dir = substream->stream;
686
687         return 0;
688 }
689
690 const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
691         .startup        = acp_i2s_startup,
692         .hw_params      = acp_i2s_hwparams,
693         .prepare        = acp_i2s_prepare,
694         .trigger        = acp_i2s_trigger,
695         .set_fmt        = acp_i2s_set_fmt,
696         .set_tdm_slot   = acp_i2s_set_tdm_slot,
697 };
698 EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, "SND_SOC_ACP_COMMON");
699
700 MODULE_DESCRIPTION("AMD ACP Audio I2S controller");
701 MODULE_LICENSE("Dual BSD/GPL");
702 MODULE_ALIAS(DRV_NAME);
This page took 0.075805 seconds and 4 git commands to generate.