Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
0002 //
0003 // This file is provided under a dual BSD/GPLv2 license. When using or
0004 // redistributing this file, you may do so under either license.
0005 //
0006 // Copyright(c) 2021 Advanced Micro Devices, Inc.
0007 //
0008 // Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
0009 //
0010 
0011 /*
0012  * Generic Hardware interface for ACP Audio I2S controller
0013  */
0014 
0015 #include <linux/platform_device.h>
0016 #include <linux/module.h>
0017 #include <linux/err.h>
0018 #include <linux/io.h>
0019 #include <sound/pcm_params.h>
0020 #include <sound/soc.h>
0021 #include <sound/soc-dai.h>
0022 #include <linux/dma-mapping.h>
0023 
0024 #include "amd.h"
0025 
0026 #define DRV_NAME "acp_i2s_playcap"
0027 
0028 static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
0029                 struct snd_soc_dai *dai)
0030 {
0031     struct device *dev = dai->component->dev;
0032     struct acp_dev_data *adata;
0033     struct acp_resource *rsrc;
0034     u32 val;
0035     u32 xfer_resolution;
0036     u32 reg_val;
0037     u32 lrclk_div_val, bclk_div_val;
0038 
0039     adata = snd_soc_dai_get_drvdata(dai);
0040     rsrc = adata->rsrc;
0041 
0042     /* These values are as per Hardware Spec */
0043     switch (params_format(params)) {
0044     case SNDRV_PCM_FORMAT_U8:
0045     case SNDRV_PCM_FORMAT_S8:
0046         xfer_resolution = 0x0;
0047         break;
0048     case SNDRV_PCM_FORMAT_S16_LE:
0049         xfer_resolution = 0x02;
0050         break;
0051     case SNDRV_PCM_FORMAT_S24_LE:
0052         xfer_resolution = 0x04;
0053         break;
0054     case SNDRV_PCM_FORMAT_S32_LE:
0055         xfer_resolution = 0x05;
0056         break;
0057     default:
0058         return -EINVAL;
0059     }
0060 
0061     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0062         switch (dai->driver->id) {
0063         case I2S_BT_INSTANCE:
0064             reg_val = ACP_BTTDM_ITER;
0065             break;
0066         case I2S_SP_INSTANCE:
0067             reg_val = ACP_I2STDM_ITER;
0068             break;
0069         case I2S_HS_INSTANCE:
0070             reg_val = ACP_HSTDM_ITER;
0071             break;
0072         default:
0073             dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
0074             return -EINVAL;
0075         }
0076     } else {
0077         switch (dai->driver->id) {
0078         case I2S_BT_INSTANCE:
0079             reg_val = ACP_BTTDM_IRER;
0080             break;
0081         case I2S_SP_INSTANCE:
0082             reg_val = ACP_I2STDM_IRER;
0083             break;
0084         case I2S_HS_INSTANCE:
0085             reg_val = ACP_HSTDM_IRER;
0086             break;
0087         default:
0088             dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
0089             return -EINVAL;
0090         }
0091     }
0092 
0093     val = readl(adata->acp_base + reg_val);
0094     val &= ~ACP3x_ITER_IRER_SAMP_LEN_MASK;
0095     val = val | (xfer_resolution  << 3);
0096     writel(val, adata->acp_base + reg_val);
0097 
0098     if (rsrc->soc_mclk) {
0099         switch (params_format(params)) {
0100         case SNDRV_PCM_FORMAT_S16_LE:
0101             switch (params_rate(params)) {
0102             case 8000:
0103                 bclk_div_val = 768;
0104                 break;
0105             case 16000:
0106                 bclk_div_val = 384;
0107                 break;
0108             case 24000:
0109                 bclk_div_val = 256;
0110                 break;
0111             case 32000:
0112                 bclk_div_val = 192;
0113                 break;
0114             case 44100:
0115             case 48000:
0116                 bclk_div_val = 128;
0117                 break;
0118             case 88200:
0119             case 96000:
0120                 bclk_div_val = 64;
0121                 break;
0122             case 192000:
0123                 bclk_div_val = 32;
0124                 break;
0125             default:
0126                 return -EINVAL;
0127             }
0128             lrclk_div_val = 32;
0129             break;
0130         case SNDRV_PCM_FORMAT_S32_LE:
0131             switch (params_rate(params)) {
0132             case 8000:
0133                 bclk_div_val = 384;
0134                 break;
0135             case 16000:
0136                 bclk_div_val = 192;
0137                 break;
0138             case 24000:
0139                 bclk_div_val = 128;
0140                 break;
0141             case 32000:
0142                 bclk_div_val = 96;
0143                 break;
0144             case 44100:
0145             case 48000:
0146                 bclk_div_val = 64;
0147                 break;
0148             case 88200:
0149             case 96000:
0150                 bclk_div_val = 32;
0151                 break;
0152             case 192000:
0153                 bclk_div_val = 16;
0154                 break;
0155             default:
0156                 return -EINVAL;
0157             }
0158             lrclk_div_val = 64;
0159             break;
0160         default:
0161             return -EINVAL;
0162         }
0163         adata->lrclk_div = lrclk_div_val;
0164         adata->bclk_div = bclk_div_val;
0165     }
0166     return 0;
0167 }
0168 
0169 static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
0170 {
0171     struct acp_stream *stream = substream->runtime->private_data;
0172     struct device *dev = dai->component->dev;
0173     struct acp_dev_data *adata = dev_get_drvdata(dev);
0174     struct acp_resource *rsrc = adata->rsrc;
0175     u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg;
0176 
0177     period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size);
0178     buf_size = frames_to_bytes(substream->runtime, substream->runtime->buffer_size);
0179 
0180     switch (cmd) {
0181     case SNDRV_PCM_TRIGGER_START:
0182     case SNDRV_PCM_TRIGGER_RESUME:
0183     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0184         stream->bytescount = acp_get_byte_count(adata, stream->dai_id, substream->stream);
0185         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0186             switch (dai->driver->id) {
0187             case I2S_BT_INSTANCE:
0188                 water_val = ACP_BT_TX_INTR_WATERMARK_SIZE;
0189                 reg_val = ACP_BTTDM_ITER;
0190                 ier_val = ACP_BTTDM_IER;
0191                 buf_reg = ACP_BT_TX_RINGBUFSIZE;
0192                 break;
0193             case I2S_SP_INSTANCE:
0194                 water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE;
0195                 reg_val = ACP_I2STDM_ITER;
0196                 ier_val = ACP_I2STDM_IER;
0197                 buf_reg = ACP_I2S_TX_RINGBUFSIZE;
0198                 break;
0199             case I2S_HS_INSTANCE:
0200                 water_val = ACP_HS_TX_INTR_WATERMARK_SIZE;
0201                 reg_val = ACP_HSTDM_ITER;
0202                 ier_val = ACP_HSTDM_IER;
0203                 buf_reg = ACP_HS_TX_RINGBUFSIZE;
0204                 break;
0205             default:
0206                 dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
0207                 return -EINVAL;
0208             }
0209         } else {
0210             switch (dai->driver->id) {
0211             case I2S_BT_INSTANCE:
0212                 water_val = ACP_BT_RX_INTR_WATERMARK_SIZE;
0213                 reg_val = ACP_BTTDM_IRER;
0214                 ier_val = ACP_BTTDM_IER;
0215                 buf_reg = ACP_BT_RX_RINGBUFSIZE;
0216                 break;
0217             case I2S_SP_INSTANCE:
0218                 water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE;
0219                 reg_val = ACP_I2STDM_IRER;
0220                 ier_val = ACP_I2STDM_IER;
0221                 buf_reg = ACP_I2S_RX_RINGBUFSIZE;
0222                 break;
0223             case I2S_HS_INSTANCE:
0224                 water_val = ACP_HS_RX_INTR_WATERMARK_SIZE;
0225                 reg_val = ACP_HSTDM_IRER;
0226                 ier_val = ACP_HSTDM_IER;
0227                 buf_reg = ACP_HS_RX_RINGBUFSIZE;
0228                 break;
0229             default:
0230                 dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
0231                 return -EINVAL;
0232             }
0233         }
0234         writel(period_bytes, adata->acp_base + water_val);
0235         writel(buf_size, adata->acp_base + buf_reg);
0236         val = readl(adata->acp_base + reg_val);
0237         val = val | BIT(0);
0238         writel(val, adata->acp_base + reg_val);
0239         writel(1, adata->acp_base + ier_val);
0240         if (rsrc->soc_mclk)
0241             acp_set_i2s_clk(adata, dai->driver->id);
0242         return 0;
0243     case SNDRV_PCM_TRIGGER_STOP:
0244     case SNDRV_PCM_TRIGGER_SUSPEND:
0245     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0246         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0247             switch (dai->driver->id) {
0248             case I2S_BT_INSTANCE:
0249                 reg_val = ACP_BTTDM_ITER;
0250                 break;
0251             case I2S_SP_INSTANCE:
0252                 reg_val = ACP_I2STDM_ITER;
0253                 break;
0254             case I2S_HS_INSTANCE:
0255                 reg_val = ACP_HSTDM_ITER;
0256                 break;
0257             default:
0258                 dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
0259                 return -EINVAL;
0260             }
0261 
0262         } else {
0263             switch (dai->driver->id) {
0264             case I2S_BT_INSTANCE:
0265                 reg_val = ACP_BTTDM_IRER;
0266                 break;
0267             case I2S_SP_INSTANCE:
0268                 reg_val = ACP_I2STDM_IRER;
0269                 break;
0270             case I2S_HS_INSTANCE:
0271                 reg_val = ACP_HSTDM_IRER;
0272                 break;
0273             default:
0274                 dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
0275                 return -EINVAL;
0276             }
0277         }
0278         val = readl(adata->acp_base + reg_val);
0279         val = val & ~BIT(0);
0280         writel(val, adata->acp_base + reg_val);
0281 
0282         if (!(readl(adata->acp_base + ACP_BTTDM_ITER) & BIT(0)) &&
0283             !(readl(adata->acp_base + ACP_BTTDM_IRER) & BIT(0)))
0284             writel(0, adata->acp_base + ACP_BTTDM_IER);
0285         if (!(readl(adata->acp_base + ACP_I2STDM_ITER) & BIT(0)) &&
0286             !(readl(adata->acp_base + ACP_I2STDM_IRER) & BIT(0)))
0287             writel(0, adata->acp_base + ACP_I2STDM_IER);
0288         if (!(readl(adata->acp_base + ACP_HSTDM_ITER) & BIT(0)) &&
0289             !(readl(adata->acp_base + ACP_HSTDM_IRER) & BIT(0)))
0290             writel(0, adata->acp_base + ACP_HSTDM_IER);
0291         return 0;
0292     default:
0293         return -EINVAL;
0294     }
0295 
0296     return 0;
0297 }
0298 
0299 static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
0300 {
0301     struct device *dev = dai->component->dev;
0302     struct acp_dev_data *adata = dev_get_drvdata(dev);
0303     struct acp_resource *rsrc = adata->rsrc;
0304     struct acp_stream *stream = substream->runtime->private_data;
0305     u32 reg_dma_size = 0, reg_fifo_size = 0, reg_fifo_addr = 0;
0306     u32 phy_addr = 0, acp_fifo_addr = 0, ext_int_ctrl;
0307     unsigned int dir = substream->stream;
0308 
0309     switch (dai->driver->id) {
0310     case I2S_SP_INSTANCE:
0311         if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
0312             reg_dma_size = ACP_I2S_TX_DMA_SIZE;
0313             acp_fifo_addr = rsrc->sram_pte_offset +
0314                         SP_PB_FIFO_ADDR_OFFSET;
0315             reg_fifo_addr = ACP_I2S_TX_FIFOADDR;
0316             reg_fifo_size = ACP_I2S_TX_FIFOSIZE;
0317 
0318             phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
0319             writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR);
0320         } else {
0321             reg_dma_size = ACP_I2S_RX_DMA_SIZE;
0322             acp_fifo_addr = rsrc->sram_pte_offset +
0323                         SP_CAPT_FIFO_ADDR_OFFSET;
0324             reg_fifo_addr = ACP_I2S_RX_FIFOADDR;
0325             reg_fifo_size = ACP_I2S_RX_FIFOSIZE;
0326             phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
0327             writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR);
0328         }
0329         break;
0330     case I2S_BT_INSTANCE:
0331         if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
0332             reg_dma_size = ACP_BT_TX_DMA_SIZE;
0333             acp_fifo_addr = rsrc->sram_pte_offset +
0334                         BT_PB_FIFO_ADDR_OFFSET;
0335             reg_fifo_addr = ACP_BT_TX_FIFOADDR;
0336             reg_fifo_size = ACP_BT_TX_FIFOSIZE;
0337 
0338             phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
0339             writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR);
0340         } else {
0341             reg_dma_size = ACP_BT_RX_DMA_SIZE;
0342             acp_fifo_addr = rsrc->sram_pte_offset +
0343                         BT_CAPT_FIFO_ADDR_OFFSET;
0344             reg_fifo_addr = ACP_BT_RX_FIFOADDR;
0345             reg_fifo_size = ACP_BT_RX_FIFOSIZE;
0346 
0347             phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
0348             writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR);
0349         }
0350         break;
0351     case I2S_HS_INSTANCE:
0352         if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
0353             reg_dma_size = ACP_HS_TX_DMA_SIZE;
0354             acp_fifo_addr = rsrc->sram_pte_offset +
0355                 HS_PB_FIFO_ADDR_OFFSET;
0356             reg_fifo_addr = ACP_HS_TX_FIFOADDR;
0357             reg_fifo_size = ACP_HS_TX_FIFOSIZE;
0358 
0359             phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
0360             writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR);
0361         } else {
0362             reg_dma_size = ACP_HS_RX_DMA_SIZE;
0363             acp_fifo_addr = rsrc->sram_pte_offset +
0364                     HS_CAPT_FIFO_ADDR_OFFSET;
0365             reg_fifo_addr = ACP_HS_RX_FIFOADDR;
0366             reg_fifo_size = ACP_HS_RX_FIFOSIZE;
0367 
0368             phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
0369             writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR);
0370         }
0371         break;
0372     default:
0373         dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
0374         return -EINVAL;
0375     }
0376 
0377     writel(DMA_SIZE, adata->acp_base + reg_dma_size);
0378     writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr);
0379     writel(FIFO_SIZE, adata->acp_base + reg_fifo_size);
0380 
0381     ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
0382     ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) |
0383             BIT(BT_RX_THRESHOLD(rsrc->offset)) |
0384             BIT(I2S_TX_THRESHOLD(rsrc->offset)) |
0385             BIT(BT_TX_THRESHOLD(rsrc->offset)) |
0386             BIT(HS_RX_THRESHOLD(rsrc->offset)) |
0387             BIT(HS_TX_THRESHOLD(rsrc->offset));
0388 
0389     writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
0390 
0391     return 0;
0392 }
0393 
0394 static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
0395 {
0396     struct acp_stream *stream = substream->runtime->private_data;
0397     struct device *dev = dai->component->dev;
0398     struct acp_dev_data *adata = dev_get_drvdata(dev);
0399     struct acp_resource *rsrc = adata->rsrc;
0400     unsigned int dir = substream->stream;
0401     unsigned int irq_bit = 0;
0402 
0403     switch (dai->driver->id) {
0404     case I2S_SP_INSTANCE:
0405         if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
0406             irq_bit = BIT(I2S_TX_THRESHOLD(rsrc->offset));
0407             stream->pte_offset = ACP_SRAM_SP_PB_PTE_OFFSET;
0408             stream->fifo_offset = SP_PB_FIFO_ADDR_OFFSET;
0409         } else {
0410             irq_bit = BIT(I2S_RX_THRESHOLD(rsrc->offset));
0411             stream->pte_offset = ACP_SRAM_SP_CP_PTE_OFFSET;
0412             stream->fifo_offset = SP_CAPT_FIFO_ADDR_OFFSET;
0413         }
0414         break;
0415     case I2S_BT_INSTANCE:
0416         if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
0417             irq_bit = BIT(BT_TX_THRESHOLD(rsrc->offset));
0418             stream->pte_offset = ACP_SRAM_BT_PB_PTE_OFFSET;
0419             stream->fifo_offset = BT_PB_FIFO_ADDR_OFFSET;
0420         } else {
0421             irq_bit = BIT(BT_RX_THRESHOLD(rsrc->offset));
0422             stream->pte_offset = ACP_SRAM_BT_CP_PTE_OFFSET;
0423             stream->fifo_offset = BT_CAPT_FIFO_ADDR_OFFSET;
0424         }
0425         break;
0426     case I2S_HS_INSTANCE:
0427         if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
0428             irq_bit = BIT(HS_TX_THRESHOLD(rsrc->offset));
0429             stream->pte_offset = ACP_SRAM_HS_PB_PTE_OFFSET;
0430             stream->fifo_offset = HS_PB_FIFO_ADDR_OFFSET;
0431         } else {
0432             irq_bit = BIT(HS_RX_THRESHOLD(rsrc->offset));
0433             stream->pte_offset = ACP_SRAM_HS_CP_PTE_OFFSET;
0434             stream->fifo_offset = HS_CAPT_FIFO_ADDR_OFFSET;
0435         }
0436         break;
0437     default:
0438         dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
0439         return -EINVAL;
0440     }
0441 
0442     /* Save runtime dai configuration in stream */
0443     stream->id = dai->driver->id + dir;
0444     stream->dai_id = dai->driver->id;
0445     stream->irq_bit = irq_bit;
0446 
0447     return 0;
0448 }
0449 
0450 const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
0451     .startup = acp_i2s_startup,
0452     .hw_params = acp_i2s_hwparams,
0453     .prepare = acp_i2s_prepare,
0454     .trigger = acp_i2s_trigger,
0455 };
0456 EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON);
0457 
0458 int asoc_acp_i2s_probe(struct snd_soc_dai *dai)
0459 {
0460     struct device *dev = dai->component->dev;
0461     struct acp_dev_data *adata = dev_get_drvdata(dev);
0462     struct acp_resource *rsrc = adata->rsrc;
0463     unsigned int val;
0464 
0465     if (!adata->acp_base) {
0466         dev_err(dev, "I2S base is NULL\n");
0467         return -EINVAL;
0468     }
0469 
0470     val = readl(adata->acp_base + rsrc->i2s_pin_cfg_offset);
0471     if (val != rsrc->i2s_mode) {
0472         dev_err(dev, "I2S Mode not supported val %x\n", val);
0473         return -EINVAL;
0474     }
0475 
0476     return 0;
0477 }
0478 EXPORT_SYMBOL_NS_GPL(asoc_acp_i2s_probe, SND_SOC_ACP_COMMON);
0479 
0480 MODULE_LICENSE("Dual BSD/GPL");
0481 MODULE_ALIAS(DRV_NAME);