cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

acp-renoir.c (7473B)


      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 <AjitKumar.Pandey@amd.com>
      9//
     10
     11/*
     12 * Hardware interface for Renoir ACP block
     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
     24#include "amd.h"
     25
     26#define DRV_NAME "acp_asoc_renoir"
     27
     28#define ACP_SOFT_RST_DONE_MASK	0x00010001
     29
     30#define ACP_PWR_ON_MASK		0x01
     31#define ACP_PWR_OFF_MASK	0x00
     32#define ACP_PGFSM_STAT_MASK	0x03
     33#define ACP_POWERED_ON		0x00
     34#define ACP_PWR_ON_IN_PROGRESS	0x01
     35#define ACP_POWERED_OFF		0x02
     36#define DELAY_US		5
     37#define ACP_TIMEOUT		500
     38
     39#define ACP_ERROR_MASK 0x20000000
     40#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF
     41
     42static struct snd_soc_acpi_codecs amp_rt1019 = {
     43	.num_codecs = 1,
     44	.codecs = {"10EC1019"}
     45};
     46
     47static struct snd_soc_acpi_codecs amp_max = {
     48	.num_codecs = 1,
     49	.codecs = {"MX98360A"}
     50};
     51
     52static struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[] = {
     53	{
     54		.id = "10EC5682",
     55		.drv_name = "acp3xalc56821019",
     56		.machine_quirk = snd_soc_acpi_codec_list,
     57		.quirk_data = &amp_rt1019,
     58	},
     59	{
     60		.id = "RTL5682",
     61		.drv_name = "acp3xalc5682sm98360",
     62		.machine_quirk = snd_soc_acpi_codec_list,
     63		.quirk_data = &amp_max,
     64	},
     65	{
     66		.id = "RTL5682",
     67		.drv_name = "acp3xalc5682s1019",
     68		.machine_quirk = snd_soc_acpi_codec_list,
     69		.quirk_data = &amp_rt1019,
     70	},
     71	{
     72		.id = "AMDI1019",
     73		.drv_name = "renoir-acp",
     74	},
     75	{},
     76};
     77
     78static struct snd_soc_dai_driver acp_renoir_dai[] = {
     79{
     80	.name = "acp-i2s-sp",
     81	.id = I2S_SP_INSTANCE,
     82	.playback = {
     83		.stream_name = "I2S SP Playback",
     84		.rates = SNDRV_PCM_RATE_8000_96000,
     85		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
     86			   SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
     87		.channels_min = 2,
     88		.channels_max = 8,
     89		.rate_min = 8000,
     90		.rate_max = 96000,
     91	},
     92	.capture = {
     93		.stream_name = "I2S SP Capture",
     94		.rates = SNDRV_PCM_RATE_8000_48000,
     95		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
     96			   SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
     97		.channels_min = 2,
     98		.channels_max = 2,
     99		.rate_min = 8000,
    100		.rate_max = 48000,
    101	},
    102	.ops = &asoc_acp_cpu_dai_ops,
    103	.probe = &asoc_acp_i2s_probe,
    104},
    105{
    106	.name = "acp-i2s-bt",
    107	.id = I2S_BT_INSTANCE,
    108	.playback = {
    109		.stream_name = "I2S BT Playback",
    110		.rates = SNDRV_PCM_RATE_8000_96000,
    111		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
    112			   SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
    113		.channels_min = 2,
    114		.channels_max = 8,
    115		.rate_min = 8000,
    116		.rate_max = 96000,
    117	},
    118	.capture = {
    119		.stream_name = "I2S BT Capture",
    120		.rates = SNDRV_PCM_RATE_8000_48000,
    121		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
    122			   SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
    123		.channels_min = 2,
    124		.channels_max = 2,
    125		.rate_min = 8000,
    126		.rate_max = 48000,
    127	},
    128	.ops = &asoc_acp_cpu_dai_ops,
    129	.probe = &asoc_acp_i2s_probe,
    130},
    131{
    132	.name = "acp-pdm-dmic",
    133	.id = DMIC_INSTANCE,
    134	.capture = {
    135		.rates = SNDRV_PCM_RATE_8000_48000,
    136		.formats = SNDRV_PCM_FMTBIT_S32_LE,
    137		.channels_min = 2,
    138		.channels_max = 2,
    139		.rate_min = 8000,
    140		.rate_max = 48000,
    141	},
    142	.ops = &acp_dmic_dai_ops,
    143},
    144};
    145
    146static int acp3x_power_on(void __iomem *base)
    147{
    148	u32 val;
    149
    150	val = readl(base + ACP_PGFSM_STATUS);
    151
    152	if (val == ACP_POWERED_ON)
    153		return 0;
    154
    155	if ((val & ACP_PGFSM_STAT_MASK) != ACP_PWR_ON_IN_PROGRESS)
    156		writel(ACP_PWR_ON_MASK, base + ACP_PGFSM_CONTROL);
    157
    158	return readl_poll_timeout(base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP_TIMEOUT);
    159}
    160
    161static int acp3x_power_off(void __iomem *base)
    162{
    163	u32 val;
    164
    165	writel(ACP_PWR_OFF_MASK, base + ACP_PGFSM_CONTROL);
    166
    167	return readl_poll_timeout(base + ACP_PGFSM_STATUS, val,
    168				  (val & ACP_PGFSM_STAT_MASK) == ACP_POWERED_OFF,
    169				  DELAY_US, ACP_TIMEOUT);
    170}
    171
    172static int acp3x_reset(void __iomem *base)
    173{
    174	u32 val;
    175	int ret;
    176
    177	writel(1, base + ACP_SOFT_RESET);
    178
    179	ret = readl_poll_timeout(base + ACP_SOFT_RESET, val, val & ACP_SOFT_RST_DONE_MASK,
    180				 DELAY_US, ACP_TIMEOUT);
    181	if (ret)
    182		return ret;
    183
    184	writel(0, base + ACP_SOFT_RESET);
    185
    186	return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT);
    187}
    188
    189static void acp3x_enable_interrupts(void __iomem *base)
    190{
    191	u32 ext_intr_ctrl;
    192
    193	writel(0x01, base + ACP_EXTERNAL_INTR_ENB);
    194	ext_intr_ctrl = readl(base + ACP_EXTERNAL_INTR_CNTL);
    195	ext_intr_ctrl |= ACP_ERROR_MASK;
    196	writel(ext_intr_ctrl, base + ACP_EXTERNAL_INTR_CNTL);
    197}
    198
    199static void acp3x_disable_interrupts(void __iomem *base)
    200{
    201	writel(ACP_EXT_INTR_STAT_CLEAR_MASK, base + ACP_EXTERNAL_INTR_STAT);
    202	writel(0x00, base + ACP_EXTERNAL_INTR_ENB);
    203}
    204
    205static int rn_acp_init(void __iomem *base)
    206{
    207	int ret;
    208
    209	/* power on */
    210	ret = acp3x_power_on(base);
    211	if (ret)
    212		return ret;
    213
    214	writel(0x01, base + ACP_CONTROL);
    215
    216	/* Reset */
    217	ret = acp3x_reset(base);
    218	if (ret)
    219		return ret;
    220
    221	acp3x_enable_interrupts(base);
    222
    223	return 0;
    224}
    225
    226static int rn_acp_deinit(void __iomem *base)
    227{
    228	int ret = 0;
    229
    230	acp3x_disable_interrupts(base);
    231
    232	/* Reset */
    233	ret = acp3x_reset(base);
    234	if (ret)
    235		return ret;
    236
    237	writel(0x00, base + ACP_CONTROL);
    238
    239	/* power off */
    240	ret = acp3x_power_off(base);
    241	if (ret)
    242		return ret;
    243
    244	return 0;
    245}
    246static int renoir_audio_probe(struct platform_device *pdev)
    247{
    248	struct device *dev = &pdev->dev;
    249	struct acp_chip_info *chip;
    250	struct acp_dev_data *adata;
    251	struct resource *res;
    252	int ret;
    253
    254	chip = dev_get_platdata(&pdev->dev);
    255	if (!chip || !chip->base) {
    256		dev_err(&pdev->dev, "ACP chip data is NULL\n");
    257		return -ENODEV;
    258	}
    259
    260	if (chip->acp_rev != ACP3X_DEV) {
    261		dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
    262		return -ENODEV;
    263	}
    264
    265	ret = rn_acp_init(chip->base);
    266	if (ret) {
    267		dev_err(&pdev->dev, "ACP Init failed\n");
    268		return -EINVAL;
    269	}
    270
    271	adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL);
    272	if (!adata)
    273		return -ENOMEM;
    274
    275	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem");
    276	if (!res) {
    277		dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
    278		return -ENODEV;
    279	}
    280
    281	adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
    282	if (!adata->acp_base)
    283		return -ENOMEM;
    284
    285	ret = platform_get_irq_byname(pdev, "acp_dai_irq");
    286	if (ret < 0)
    287		return ret;
    288	adata->i2s_irq = ret;
    289
    290	adata->dev = dev;
    291	adata->dai_driver = acp_renoir_dai;
    292	adata->num_dai = ARRAY_SIZE(acp_renoir_dai);
    293
    294	adata->machines = snd_soc_acpi_amd_acp_machines;
    295	acp_machine_select(adata);
    296
    297	dev_set_drvdata(dev, adata);
    298	acp_platform_register(dev);
    299
    300	return 0;
    301}
    302
    303static int renoir_audio_remove(struct platform_device *pdev)
    304{
    305	struct device *dev = &pdev->dev;
    306	struct acp_chip_info *chip;
    307	int ret;
    308
    309	chip = dev_get_platdata(&pdev->dev);
    310	if (!chip || !chip->base) {
    311		dev_err(&pdev->dev, "ACP chip data is NULL\n");
    312		return -ENODEV;
    313	}
    314
    315	ret = rn_acp_deinit(chip->base);
    316	if (ret) {
    317		dev_err(&pdev->dev, "ACP de-init Failed\n");
    318		return -EINVAL;
    319	}
    320
    321	acp_platform_unregister(dev);
    322	return 0;
    323}
    324
    325static struct platform_driver renoir_driver = {
    326	.probe = renoir_audio_probe,
    327	.remove = renoir_audio_remove,
    328	.driver = {
    329		.name = "acp_asoc_renoir",
    330	},
    331};
    332
    333module_platform_driver(renoir_driver);
    334
    335MODULE_DESCRIPTION("AMD ACP Renoir Driver");
    336MODULE_IMPORT_NS(SND_SOC_ACP_COMMON);
    337MODULE_LICENSE("Dual BSD/GPL");
    338MODULE_ALIAS("platform:" DRV_NAME);