brintos

brintos / linux-shallow public Read only

0
0
Text · 7.7 KiB · 396434a Raw
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 = &amp_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 = &amp_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