311 lines · 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 or4// redistributing this file, you may do so under either license.5//6// Copyright(c) 2022 Advanced Micro Devices, Inc.7//8// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>9// V sujith kumar Reddy <Vsujithkumar.Reddy@amd.com>10/*11 * Hardware interface for Renoir ACP block12 */13 14#include <linux/platform_device.h>15#include <linux/module.h>16#include <linux/err.h>17#include <linux/io.h>18#include <sound/pcm_params.h>19#include <sound/soc.h>20#include <sound/soc-dai.h>21#include <linux/dma-mapping.h>22#include <linux/pci.h>23#include <linux/pm_runtime.h>24 25#include "amd.h"26#include "../mach-config.h"27#include "acp-mach.h"28 29#define DRV_NAME "acp_asoc_rembrandt"30 31#define MP1_C2PMSG_69 0x3B10A1432#define MP1_C2PMSG_85 0x3B10A5433#define MP1_C2PMSG_93 0x3B10A7434#define HOST_BRIDGE_ID 0x14B535 36static struct acp_resource rsrc = {37 .offset = 0,38 .no_of_ctrls = 2,39 .irqp_used = 1,40 .soc_mclk = true,41 .irq_reg_offset = 0x1a00,42 .scratch_reg_offset = 0x12800,43 .sram_pte_offset = 0x03802800,44};45 46static struct snd_soc_acpi_codecs amp_rt1019 = {47 .num_codecs = 1,48 .codecs = {"10EC1019"}49};50 51static struct snd_soc_acpi_codecs amp_max = {52 .num_codecs = 1,53 .codecs = {"MX98360A"}54};55 56static struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines[] = {57 {58 .id = "10508825",59 .drv_name = "rmb-nau8825-max",60 .machine_quirk = snd_soc_acpi_codec_list,61 .quirk_data = &_max,62 },63 {64 .id = "AMDI0007",65 .drv_name = "rembrandt-acp",66 },67 {68 .id = "RTL5682",69 .drv_name = "rmb-rt5682s-rt1019",70 .machine_quirk = snd_soc_acpi_codec_list,71 .quirk_data = &_rt1019,72 },73 {},74};75 76static struct snd_soc_dai_driver acp_rmb_dai[] = {77{78 .name = "acp-i2s-sp",79 .id = I2S_SP_INSTANCE,80 .playback = {81 .stream_name = "I2S SP Playback",82 .rates = SNDRV_PCM_RATE_8000_96000,83 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |84 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,85 .channels_min = 2,86 .channels_max = 8,87 .rate_min = 8000,88 .rate_max = 96000,89 },90 .capture = {91 .stream_name = "I2S SP Capture",92 .rates = SNDRV_PCM_RATE_8000_48000,93 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |94 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,95 .channels_min = 2,96 .channels_max = 2,97 .rate_min = 8000,98 .rate_max = 48000,99 },100 .ops = &asoc_acp_cpu_dai_ops,101},102{103 .name = "acp-i2s-bt",104 .id = I2S_BT_INSTANCE,105 .playback = {106 .stream_name = "I2S BT Playback",107 .rates = SNDRV_PCM_RATE_8000_96000,108 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |109 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,110 .channels_min = 2,111 .channels_max = 8,112 .rate_min = 8000,113 .rate_max = 96000,114 },115 .capture = {116 .stream_name = "I2S BT Capture",117 .rates = SNDRV_PCM_RATE_8000_48000,118 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |119 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,120 .channels_min = 2,121 .channels_max = 2,122 .rate_min = 8000,123 .rate_max = 48000,124 },125 .ops = &asoc_acp_cpu_dai_ops,126},127{128 .name = "acp-i2s-hs",129 .id = I2S_HS_INSTANCE,130 .playback = {131 .stream_name = "I2S HS Playback",132 .rates = SNDRV_PCM_RATE_8000_96000,133 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |134 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,135 .channels_min = 2,136 .channels_max = 8,137 .rate_min = 8000,138 .rate_max = 96000,139 },140 .capture = {141 .stream_name = "I2S HS Capture",142 .rates = SNDRV_PCM_RATE_8000_48000,143 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |144 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,145 .channels_min = 2,146 .channels_max = 8,147 .rate_min = 8000,148 .rate_max = 48000,149 },150 .ops = &asoc_acp_cpu_dai_ops,151},152{153 .name = "acp-pdm-dmic",154 .id = DMIC_INSTANCE,155 .capture = {156 .rates = SNDRV_PCM_RATE_8000_48000,157 .formats = SNDRV_PCM_FMTBIT_S32_LE,158 .channels_min = 2,159 .channels_max = 2,160 .rate_min = 8000,161 .rate_max = 48000,162 },163 .ops = &acp_dmic_dai_ops,164},165};166 167static int acp6x_master_clock_generate(struct device *dev)168{169 int data = 0;170 struct pci_dev *smn_dev;171 172 smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, HOST_BRIDGE_ID, NULL);173 if (!smn_dev) {174 dev_err(dev, "Failed to get host bridge device\n");175 return -ENODEV;176 }177 178 smn_write(smn_dev, MP1_C2PMSG_93, 0);179 smn_write(smn_dev, MP1_C2PMSG_85, 0xC4);180 smn_write(smn_dev, MP1_C2PMSG_69, 0x4);181 read_poll_timeout(smn_read, data, data, DELAY_US,182 ACP_TIMEOUT, false, smn_dev, MP1_C2PMSG_93);183 return 0;184}185 186static int rembrandt_audio_probe(struct platform_device *pdev)187{188 struct device *dev = &pdev->dev;189 struct acp_chip_info *chip;190 struct acp_dev_data *adata;191 struct resource *res;192 u32 ret;193 194 chip = dev_get_platdata(&pdev->dev);195 if (!chip || !chip->base) {196 dev_err(&pdev->dev, "ACP chip data is NULL\n");197 return -ENODEV;198 }199 200 if (chip->acp_rev != ACP6X_DEV) {201 dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);202 return -ENODEV;203 }204 205 adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL);206 if (!adata)207 return -ENOMEM;208 209 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem");210 if (!res) {211 dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");212 return -ENODEV;213 }214 215 adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));216 if (!adata->acp_base)217 return -ENOMEM;218 219 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq");220 if (!res) {221 dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");222 return -ENODEV;223 }224 225 adata->i2s_irq = res->start;226 adata->dev = dev;227 adata->dai_driver = acp_rmb_dai;228 adata->num_dai = ARRAY_SIZE(acp_rmb_dai);229 adata->rsrc = &rsrc;230 adata->platform = REMBRANDT;231 adata->flag = chip->flag;232 adata->is_i2s_config = chip->is_i2s_config;233 adata->machines = snd_soc_acpi_amd_rmb_acp_machines;234 acp_machine_select(adata);235 236 dev_set_drvdata(dev, adata);237 238 if (chip->is_i2s_config && rsrc.soc_mclk) {239 ret = acp6x_master_clock_generate(dev);240 if (ret)241 return ret;242 }243 acp_enable_interrupts(adata);244 acp_platform_register(dev);245 pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);246 pm_runtime_use_autosuspend(&pdev->dev);247 pm_runtime_mark_last_busy(&pdev->dev);248 pm_runtime_set_active(&pdev->dev);249 pm_runtime_enable(&pdev->dev);250 return 0;251}252 253static void rembrandt_audio_remove(struct platform_device *pdev)254{255 struct device *dev = &pdev->dev;256 struct acp_dev_data *adata = dev_get_drvdata(dev);257 258 acp_disable_interrupts(adata);259 acp_platform_unregister(dev);260 pm_runtime_disable(&pdev->dev);261}262 263static int __maybe_unused rmb_pcm_resume(struct device *dev)264{265 struct acp_dev_data *adata = dev_get_drvdata(dev);266 struct acp_stream *stream;267 struct snd_pcm_substream *substream;268 snd_pcm_uframes_t buf_in_frames;269 u64 buf_size;270 271 if (adata->is_i2s_config && adata->rsrc->soc_mclk)272 acp6x_master_clock_generate(dev);273 274 spin_lock(&adata->acp_lock);275 list_for_each_entry(stream, &adata->stream_list, list) {276 substream = stream->substream;277 if (substream && substream->runtime) {278 buf_in_frames = (substream->runtime->buffer_size);279 buf_size = frames_to_bytes(substream->runtime, buf_in_frames);280 config_pte_for_stream(adata, stream);281 config_acp_dma(adata, stream, buf_size);282 if (stream->dai_id)283 restore_acp_i2s_params(substream, adata, stream);284 else285 restore_acp_pdm_params(substream, adata);286 }287 }288 spin_unlock(&adata->acp_lock);289 return 0;290}291 292static const struct dev_pm_ops rmb_dma_pm_ops = {293 SET_SYSTEM_SLEEP_PM_OPS(NULL, rmb_pcm_resume)294};295 296static struct platform_driver rembrandt_driver = {297 .probe = rembrandt_audio_probe,298 .remove = rembrandt_audio_remove,299 .driver = {300 .name = "acp_asoc_rembrandt",301 .pm = &rmb_dma_pm_ops,302 },303};304 305module_platform_driver(rembrandt_driver);306 307MODULE_DESCRIPTION("AMD ACP Rembrandt Driver");308MODULE_IMPORT_NS(SND_SOC_ACP_COMMON);309MODULE_LICENSE("Dual BSD/GPL");310MODULE_ALIAS("platform:" DRV_NAME);311