| From f293e1795882af6ee460243050101c7df5b86a54 Mon Sep 17 00:00:00 2001 |
| From: V sujith kumar Reddy <vsujithkumar.reddy@amd.corp-partner.google.com> |
| Date: Tue, 11 Jul 2023 11:39:23 +0530 |
| Subject: [PATCH] CHROMIUM: ASoC: amd: acp: Legacy Phoenix driver support. |
| |
| Legacy Phoenix driver support |
| |
| BUG=b:290189450 |
| TEST=TESTED on myst |
| |
| Change-Id: Iebf21fdf0f3654f2e946ecb756d7797b6760f24d |
| Signed-off-by: V sujith kumar Reddy <vsujithkumar.reddy@amd.corp-partner.google.com> |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/4681145 |
| Commit-Queue: Baili Deng <bailideng@google.com> |
| Tested-by: Baili Deng <bailideng@google.com> |
| Reviewed-by: Baili Deng <bailideng@google.com> |
| --- |
| sound/soc/amd/acp-config.c | 2 +- |
| sound/soc/amd/acp/Kconfig | 11 + |
| sound/soc/amd/acp/Makefile | 2 + |
| sound/soc/amd/acp/acp-legacy-mach.c | 17 ++ |
| sound/soc/amd/acp/acp-mach-common.c | 37 ++- |
| sound/soc/amd/acp/acp-mach.h | 1 + |
| sound/soc/amd/acp/acp-pci.c | 4 + |
| sound/soc/amd/acp/acp-phoenix.c | 459 ++++++++++++++++++++++++++++ |
| sound/soc/amd/acp/amd.h | 5 +- |
| 9 files changed, 531 insertions(+), 7 deletions(-) |
| create mode 100644 sound/soc/amd/acp/acp-phoenix.c |
| |
| diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c |
| index 75b9b1f16bd9fac64d47f237c2e9cd8eec5ce5b0..7c6ff4ee2abbb5bb4a1dc705b6ec296bb599ad3c 100644 |
| --- a/sound/soc/amd/acp-config.c |
| +++ b/sound/soc/amd/acp-config.c |
| @@ -36,7 +36,7 @@ static const struct config_entry config_table[] = { |
| }, |
| }, |
| { |
| - .flags = FLAG_AMD_SOF, |
| + .flags = FLAG_AMD_LEGACY, |
| .device = ACP_PCI_DEV_ID, |
| .dmi_table = (const struct dmi_system_id []) { |
| { |
| diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig |
| index 631cdf96d637629cdb6606ed8652c79f3644331c..02d6c39379623286da6b08d03a816d1f76f34505 100644 |
| --- a/sound/soc/amd/acp/Kconfig |
| +++ b/sound/soc/amd/acp/Kconfig |
| @@ -57,6 +57,17 @@ config SND_AMD_ASOC_REMBRANDT |
| Say Y if you want to enable AUDIO on Rembrandt |
| If unsure select "N". |
| |
| +config SND_AMD_ASOC_PHOENIX |
| + tristate "AMD ACP ASOC Phoenix Support" |
| + select SND_SOC_AMD_ACP_PCM |
| + select SND_SOC_AMD_ACP_I2S |
| + select SND_SOC_AMD_ACP_PDM |
| + depends on X86 && PCI |
| + help |
| + This option enables Phoenix I2S support on AMD platform. |
| + Say Y if you want to enable AUDIO on Phoenix |
| + If unsure select "N". |
| + |
| config SND_SOC_AMD_MACH_COMMON |
| tristate |
| depends on X86 && PCI && I2C |
| diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile |
| index 4e65fdbc8dcab2e5e64d1be7b7ad87550a3774d3..accaba488f26e9378eea557ca3eea4541a6e28f4 100644 |
| --- a/sound/soc/amd/acp/Makefile |
| +++ b/sound/soc/amd/acp/Makefile |
| @@ -14,6 +14,7 @@ snd-acp-pci-objs := acp-pci.o |
| #platform specific driver |
| snd-acp-renoir-objs := acp-renoir.o |
| snd-acp-rembrandt-objs := acp-rembrandt.o |
| +snd-acp-phoenix-objs := acp-phoenix.o |
| |
| #machine specific driver |
| snd-acp-mach-objs := acp-mach-common.o |
| @@ -28,6 +29,7 @@ obj-$(CONFIG_SND_SOC_AMD_ACP_PCI) += snd-acp-pci.o |
| |
| obj-$(CONFIG_SND_AMD_ASOC_RENOIR) += snd-acp-renoir.o |
| obj-$(CONFIG_SND_AMD_ASOC_REMBRANDT) += snd-acp-rembrandt.o |
| +obj-$(CONFIG_SND_AMD_ASOC_PHOENIX) += snd-acp-phoenix.o |
| |
| obj-$(CONFIG_SND_SOC_AMD_MACH_COMMON) += snd-acp-mach.o |
| obj-$(CONFIG_SND_SOC_AMD_LEGACY_MACH) += snd-acp-legacy-mach.o |
| diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c |
| index 6d57d17ddfd77096ff123f3ab7e872fbd20213ab..2260c001396bbb0414487ae57c6e8649176d630f 100644 |
| --- a/sound/soc/amd/acp/acp-legacy-mach.c |
| +++ b/sound/soc/amd/acp/acp-legacy-mach.c |
| @@ -75,6 +75,18 @@ static struct acp_card_drvdata rt5682s_rt1019_rmb_data = { |
| .tdm_mode = false, |
| }; |
| |
| +static struct acp_card_drvdata rt5682s_rt1019_phx_data = { |
| + .hs_cpu_id = I2S_HS, |
| + .amp_cpu_id = I2S_HS, |
| + .dmic_cpu_id = DMIC, |
| + .hs_codec_id = RT5682S, |
| + .amp_codec_id = RT1019, |
| + .dmic_codec_id = DMIC, |
| + .soc_mclk = true, |
| + .platform = PHOENIX, |
| + .tdm_mode = false, |
| +}; |
| + |
| static int acp_asoc_probe(struct platform_device *pdev) |
| { |
| struct snd_soc_card *card = NULL; |
| @@ -135,6 +147,10 @@ static const struct platform_device_id board_ids[] = { |
| .name = "rmb-rt5682s-rt1019", |
| .driver_data = (kernel_ulong_t)&rt5682s_rt1019_rmb_data, |
| }, |
| + { |
| + .name = "phx-rt5682s-rt1019", |
| + .driver_data = (kernel_ulong_t)&rt5682s_rt1019_phx_data, |
| + }, |
| { } |
| }; |
| static struct platform_driver acp_asoc_audio = { |
| @@ -155,4 +171,5 @@ MODULE_ALIAS("platform:acp3xalc5682sm98360"); |
| MODULE_ALIAS("platform:acp3xalc5682s1019"); |
| MODULE_ALIAS("platform:rmb-nau8825-max"); |
| MODULE_ALIAS("platform:rmb-rt5682s-rt1019"); |
| +MODULE_ALIAS("platform:phx-rt5682s-rt1019"); |
| MODULE_LICENSE("GPL v2"); |
| diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c |
| index a988508a9d2e9365e21b9d9673a5c48ea1031b2f..f10fa2403b6338ee2ebb8577c52322e1299fbe8b 100644 |
| --- a/sound/soc/amd/acp/acp-mach-common.c |
| +++ b/sound/soc/amd/acp/acp-mach-common.c |
| @@ -37,7 +37,7 @@ |
| #define NAU8821_FREQ_OUT 12288000 |
| #define MAX98388_CODEC_DAI "max98388-aif1" |
| |
| -#define TDM_MODE_ENABLE 1 |
| +#define TDM_MODE_ENABLE 0 |
| |
| const struct dmi_system_id acp_quirk_table[] = { |
| { |
| @@ -484,6 +484,20 @@ static int acp_card_rt5682s_hw_params(struct snd_pcm_substream *substream, |
| dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret); |
| return ret; |
| } |
| + ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL1, RT5682S_PLL_S_BCLK1, |
| + 1536000, RT5682_PLL_FREQ); |
| + if (ret < 0) { |
| + dev_err(rtd->dev, "Failed to set codec PLL: %d\n", ret); |
| + return ret; |
| + } |
| + |
| + ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL1, |
| + RT5682_PLL_FREQ, SND_SOC_CLOCK_IN); |
| + if (ret < 0) { |
| + dev_err(rtd->dev, "Failed to set codec SYSCLK: %d\n", ret); |
| + return ret; |
| + } |
| + |
| |
| /* Set tdm/i2s1 master bclk ratio */ |
| ret = snd_soc_dai_set_bclk_ratio(codec_dai, ch * format); |
| @@ -1281,6 +1295,12 @@ static struct snd_soc_dai_link_component platform_rmb_component[] = { |
| } |
| }; |
| |
| +static struct snd_soc_dai_link_component platform_phx_component[] = { |
| + { |
| + .name = "acp_asoc_phoenix.0", |
| + } |
| +}; |
| + |
| static struct snd_soc_dai_link_component sof_component[] = { |
| { |
| .name = "0000:04:00.5", |
| @@ -1580,7 +1600,10 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) |
| links[i].id = HEADSET_BE_ID; |
| links[i].cpus = i2s_hs; |
| links[i].num_cpus = ARRAY_SIZE(i2s_hs); |
| - if (drv_data->platform == REMBRANDT) { |
| + if (drv_data->platform == PHOENIX) { |
| + links[i].platforms = platform_phx_component; |
| + links[i].num_platforms = ARRAY_SIZE(platform_phx_component); |
| + } else if (drv_data->platform == REMBRANDT) { |
| links[i].platforms = platform_rmb_component; |
| links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); |
| } else { |
| @@ -1644,7 +1667,10 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) |
| links[i].id = AMP_BE_ID; |
| links[i].cpus = i2s_hs; |
| links[i].num_cpus = ARRAY_SIZE(i2s_hs); |
| - if (drv_data->platform == REMBRANDT) { |
| + if (drv_data->platform == PHOENIX) { |
| + links[i].platforms = platform_phx_component; |
| + links[i].num_platforms = ARRAY_SIZE(platform_phx_component); |
| + } else if (drv_data->platform == REMBRANDT) { |
| links[i].platforms = platform_rmb_component; |
| links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); |
| } else { |
| @@ -1687,7 +1713,10 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) |
| } |
| links[i].cpus = pdm_dmic; |
| links[i].num_cpus = ARRAY_SIZE(pdm_dmic); |
| - if (drv_data->platform == REMBRANDT) { |
| + if (drv_data->platform == PHOENIX) { |
| + links[i].platforms = platform_phx_component; |
| + links[i].num_platforms = ARRAY_SIZE(platform_phx_component); |
| + } else if (drv_data->platform == REMBRANDT) { |
| links[i].platforms = platform_rmb_component; |
| links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); |
| } else { |
| diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h |
| index 2b3ec65940230d96255b6860671855b4986ddd0e..ba38092932aa45f7235cfe7884bed49db177a4ba 100644 |
| --- a/sound/soc/amd/acp/acp-mach.h |
| +++ b/sound/soc/amd/acp/acp-mach.h |
| @@ -48,6 +48,7 @@ enum codec_endpoints { |
| enum platform_end_point { |
| RENOIR = 0, |
| REMBRANDT, |
| + PHOENIX, |
| }; |
| |
| struct acp_card_drvdata { |
| diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c |
| index a32c14a109b77bbfa311472451c268ffc71c41ca..08fc952ba30fb830a358ab3e54dd7c113fc0ecbe 100644 |
| --- a/sound/soc/amd/acp/acp-pci.c |
| +++ b/sound/soc/amd/acp/acp-pci.c |
| @@ -87,6 +87,10 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id |
| chip->name = "acp_asoc_rembrandt"; |
| chip->acp_rev = ACP6X_DEV; |
| break; |
| + case 0x63: |
| + chip->name = "acp_asoc_phoenix"; |
| + chip->acp_rev = ACP63X_DEV; |
| + break; |
| default: |
| dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision); |
| ret = -EINVAL; |
| diff --git a/sound/soc/amd/acp/acp-phoenix.c b/sound/soc/amd/acp/acp-phoenix.c |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..25bcf3790da9a909d20e2ba889a2d915c6fdf31c |
| --- /dev/null |
| +++ b/sound/soc/amd/acp/acp-phoenix.c |
| @@ -0,0 +1,459 @@ |
| +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) |
| +// |
| +// This file is provided under a dual BSD/GPLv2 license. When using or |
| +// redistributing this file, you may do so under either license. |
| +// |
| +// Copyright(c) 2022 Advanced Micro Devices, Inc. |
| +// |
| +// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com> |
| +// V sujith kumar Reddy <Vsujithkumar.Reddy@amd.com> |
| +/* |
| + * Hardware interface for Phoenix ACP block |
| + */ |
| + |
| +#include <linux/platform_device.h> |
| +#include <linux/module.h> |
| +#include <linux/err.h> |
| +#include <linux/io.h> |
| +#include <sound/pcm_params.h> |
| +#include <sound/soc.h> |
| +#include <sound/soc-dai.h> |
| +#include <linux/dma-mapping.h> |
| +#include <linux/pci.h> |
| + |
| +#include "amd.h" |
| + |
| +#define DRV_NAME "acp_asoc_phoenix" |
| + |
| +#define ACP6X_PGFSM_CONTROL 0x1024 |
| +#define ACP6X_PGFSM_STATUS 0x1028 |
| + |
| +#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001 |
| + |
| +#define ACP_PGFSM_CNTL_POWER_ON_MASK 0x01 |
| +#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0x00 |
| +#define ACP_PGFSM_STATUS_MASK 0x03 |
| +#define ACP_POWERED_ON 0x00 |
| +#define ACP_POWER_ON_IN_PROGRESS 0x01 |
| +#define ACP_POWERED_OFF 0x02 |
| +#define ACP_POWER_OFF_IN_PROGRESS 0x03 |
| + |
| +#define ACP_ERROR_MASK 0x20000000 |
| +#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF |
| + |
| +#define CLK5_CLK_PLL_PWR_REQ_N0 0X0006C2C0 |
| +#define CLK5_SPLL_FIELD_2_N0 0X0006C114 |
| +#define CLK5_CLK_PLL_REQ_N0 0X0006C0DC |
| +#define CLK5_CLK_DFSBYPASS_CONTR 0X0006C2C8 |
| +#define CLK5_CLK_DFS_CNTL_N0 0X0006C1A4 |
| + |
| +#define PLL_AUTO_STOP_REQ BIT(4) |
| +#define PLL_AUTO_START_REQ BIT(0) |
| +#define PLL_FRANCE_EN BIT(4) |
| +#define EXIT_DPF_BYPASS_0 BIT(16) |
| +#define EXIT_DPF_BYPASS_1 BIT(17) |
| +#define CLK0_DIVIDER 0X30 |
| + |
| +union clk5_pll_req_no { |
| + struct { |
| + u32 fb_mult_int : 9; |
| + u32 reserved : 3; |
| + u32 pll_spine_div : 4; |
| + u32 gb_mult_frac : 16; |
| + } bitfields, bits; |
| +u32 clk5_pll_req_no_reg; |
| +}; |
| + |
| + |
| +static int phx_acp_init(void __iomem *base); |
| +static int phx_acp_deinit(void __iomem *base); |
| + |
| +static struct acp_resource rsrc = { |
| + .offset = 0, |
| + .no_of_ctrls = 2, |
| + .irqp_used = 1, |
| + .soc_mclk = true, |
| + .irq_reg_offset = 0x1a00, |
| + .i2s_pin_cfg_offset = 0x1440, |
| + .i2s_mode = 0x0a, |
| + .scratch_reg_offset = 0x12800, |
| + .sram_pte_offset = 0x03802800, |
| +}; |
| + |
| +static struct snd_soc_acpi_codecs amp_rt1019 = { |
| + .num_codecs = 1, |
| + .codecs = {"10EC1019"} |
| +}; |
| + |
| +static struct snd_soc_acpi_mach snd_soc_acpi_amd_phx_acp_machines[] = { |
| + { |
| + .id = "AMDI0007", |
| + .drv_name = "phoenix-acp", |
| + }, |
| + { |
| + .id = "RTL5682", |
| + .drv_name = "phx-rt5682s-rt1019", |
| + .machine_quirk = snd_soc_acpi_codec_list, |
| + .quirk_data = &_rt1019, |
| + }, |
| + {}, |
| +}; |
| + |
| +static struct snd_soc_dai_driver acp_phx_dai[] = { |
| +{ |
| + .name = "acp-i2s-sp", |
| + .id = I2S_SP_INSTANCE, |
| + .playback = { |
| + .stream_name = "I2S SP Playback", |
| + .rates = SNDRV_PCM_RATE_8000_96000, |
| + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | |
| + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, |
| + .channels_min = 2, |
| + .channels_max = 8, |
| + .rate_min = 8000, |
| + .rate_max = 96000, |
| + }, |
| + .capture = { |
| + .stream_name = "I2S SP Capture", |
| + .rates = SNDRV_PCM_RATE_8000_48000, |
| + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | |
| + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, |
| + .channels_min = 2, |
| + .channels_max = 2, |
| + .rate_min = 8000, |
| + .rate_max = 48000, |
| + }, |
| + .ops = &asoc_acp_cpu_dai_ops, |
| + .probe = &asoc_acp_i2s_probe, |
| +}, |
| +{ |
| + .name = "acp-i2s-bt", |
| + .id = I2S_BT_INSTANCE, |
| + .playback = { |
| + .stream_name = "I2S BT Playback", |
| + .rates = SNDRV_PCM_RATE_8000_96000, |
| + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | |
| + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, |
| + .channels_min = 2, |
| + .channels_max = 8, |
| + .rate_min = 8000, |
| + .rate_max = 96000, |
| + }, |
| + .capture = { |
| + .stream_name = "I2S BT Capture", |
| + .rates = SNDRV_PCM_RATE_8000_48000, |
| + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | |
| + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, |
| + .channels_min = 2, |
| + .channels_max = 2, |
| + .rate_min = 8000, |
| + .rate_max = 48000, |
| + }, |
| + .ops = &asoc_acp_cpu_dai_ops, |
| + .probe = &asoc_acp_i2s_probe, |
| +}, |
| +{ |
| + .name = "acp-i2s-hs", |
| + .id = I2S_HS_INSTANCE, |
| + .playback = { |
| + .stream_name = "I2S HS Playback", |
| + .rates = SNDRV_PCM_RATE_8000_96000, |
| + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | |
| + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, |
| + .channels_min = 2, |
| + .channels_max = 8, |
| + .rate_min = 8000, |
| + .rate_max = 96000, |
| + }, |
| + .capture = { |
| + .stream_name = "I2S HS Capture", |
| + .rates = SNDRV_PCM_RATE_8000_48000, |
| + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | |
| + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, |
| + .channels_min = 2, |
| + .channels_max = 8, |
| + .rate_min = 8000, |
| + .rate_max = 48000, |
| + }, |
| + .ops = &asoc_acp_cpu_dai_ops, |
| + .probe = &asoc_acp_i2s_probe, |
| +}, |
| +{ |
| + .name = "acp-pdm-dmic", |
| + .id = DMIC_INSTANCE, |
| + .capture = { |
| + .rates = SNDRV_PCM_RATE_8000_48000, |
| + .formats = SNDRV_PCM_FMTBIT_S32_LE, |
| + .channels_min = 2, |
| + .channels_max = 2, |
| + .rate_min = 8000, |
| + .rate_max = 48000, |
| + }, |
| + .ops = &acp_dmic_dai_ops, |
| +}, |
| +}; |
| + |
| +static int acp6x_power_on(void __iomem *base) |
| +{ |
| + u32 val; |
| + int timeout; |
| + |
| + val = readl(base + ACP6X_PGFSM_STATUS); |
| + |
| + if (val == ACP_POWERED_ON) |
| + return 0; |
| + |
| + if ((val & ACP_PGFSM_STATUS_MASK) != |
| + ACP_POWER_ON_IN_PROGRESS) |
| + writel(ACP_PGFSM_CNTL_POWER_ON_MASK, |
| + base + ACP6X_PGFSM_CONTROL); |
| + timeout = 0; |
| + while (++timeout < 500) { |
| + val = readl(base + ACP6X_PGFSM_STATUS); |
| + if (!val) |
| + return 0; |
| + udelay(1); |
| + } |
| + return -ETIMEDOUT; |
| +} |
| + |
| +static int acp6x_power_off(void __iomem *base) |
| +{ |
| + u32 val; |
| + int timeout; |
| + |
| + writel(ACP_PGFSM_CNTL_POWER_OFF_MASK, |
| + base + ACP6X_PGFSM_CONTROL); |
| + timeout = 0; |
| + while (++timeout < 500) { |
| + val = readl(base + ACP6X_PGFSM_STATUS); |
| + if ((val & ACP_PGFSM_STATUS_MASK) == ACP_POWERED_OFF) |
| + return 0; |
| + udelay(1); |
| + } |
| + return -ETIMEDOUT; |
| +} |
| + |
| +static int acp6x_reset(void __iomem *base) |
| +{ |
| + u32 val; |
| + int timeout; |
| + |
| + writel(1, base + ACP_SOFT_RESET); |
| + timeout = 0; |
| + while (++timeout < 500) { |
| + val = readl(base + ACP_SOFT_RESET); |
| + if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK) |
| + break; |
| + cpu_relax(); |
| + } |
| + writel(0, base + ACP_SOFT_RESET); |
| + timeout = 0; |
| + while (++timeout < 500) { |
| + val = readl(base + ACP_SOFT_RESET); |
| + if (!val) |
| + return 0; |
| + cpu_relax(); |
| + } |
| + return -ETIMEDOUT; |
| +} |
| +static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) |
| +{ |
| + pci_write_config_dword(dev, 0x60, smn_addr); |
| + pci_write_config_dword(dev, 0x64, data); |
| + |
| + return 0; |
| +} |
| + |
| +static int smn_read(struct pci_dev *dev, u32 smn_addr) |
| +{ |
| + u32 data; |
| + pci_write_config_dword(dev, 0x60, smn_addr); |
| + pci_read_config_dword(dev, 0x64, &data); |
| + |
| + return data; |
| +} |
| + |
| +void acp63_master_clock_generate(struct acp_dev_data *adata) |
| +{ |
| + u32 data; |
| + union clk5_pll_req_no clk5_pll; |
| + struct pci_dev *smn_dev; |
| + |
| + smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x14E8, NULL); |
| + if (!smn_dev) { |
| + pr_err("sujith Failed to get host bridge device\n"); |
| + return; |
| + } |
| + /* Clk5 pll register values to get mclk as 196.6MHz*/ |
| + clk5_pll.bits.fb_mult_int = 0x31; |
| + clk5_pll.bits.pll_spine_div = 0; |
| + clk5_pll.bits.gb_mult_frac = 0x26E9; |
| + |
| + data = smn_read(smn_dev, CLK5_CLK_PLL_PWR_REQ_N0); |
| + smn_write(smn_dev, CLK5_CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_STOP_REQ); |
| + |
| + data = smn_read(smn_dev, CLK5_SPLL_FIELD_2_N0); |
| + if (data & PLL_FRANCE_EN) |
| + smn_write(smn_dev, CLK5_SPLL_FIELD_2_N0, data | PLL_FRANCE_EN); |
| + |
| + smn_write(smn_dev, CLK5_CLK_PLL_REQ_N0, clk5_pll.clk5_pll_req_no_reg); |
| + |
| + data = smn_read(smn_dev, CLK5_CLK_PLL_PWR_REQ_N0); |
| + smn_write(smn_dev, CLK5_CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_START_REQ); |
| + |
| + data = smn_read(smn_dev, CLK5_CLK_DFSBYPASS_CONTR); |
| + smn_write(smn_dev, CLK5_CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_0); |
| + smn_write(smn_dev, CLK5_CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_1); |
| + |
| + smn_write(smn_dev, CLK5_CLK_DFS_CNTL_N0, CLK0_DIVIDER); |
| +} |
| + |
| +static void acp6x_enable_interrupts(struct acp_dev_data *adata) |
| +{ |
| + struct acp_resource *rsrc = adata->rsrc; |
| + u32 ext_intr_ctrl; |
| + |
| + writel(0x01, ACP_EXTERNAL_INTR_ENB(adata)); |
| + ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); |
| + ext_intr_ctrl |= ACP_ERROR_MASK; |
| + writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); |
| + writel(0x01, adata->acp_base + 0x105C); |
| +} |
| + |
| +static void acp6x_disable_interrupts(struct acp_dev_data *adata) |
| +{ |
| + struct acp_resource *rsrc = adata->rsrc; |
| + |
| + writel(ACP_EXT_INTR_STAT_CLEAR_MASK, |
| + ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); |
| + writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); |
| +} |
| + |
| +static int phx_acp_init(void __iomem *base) |
| +{ |
| + int ret; |
| + |
| + /* power on */ |
| + ret = acp6x_power_on(base); |
| + if (ret) { |
| + pr_err("ACP power on failed\n"); |
| + return ret; |
| + } |
| + writel(0x01, base + ACP_CONTROL); |
| + |
| + /* Reset */ |
| + ret = acp6x_reset(base); |
| + if (ret) { |
| + pr_err("ACP reset failed\n"); |
| + return ret; |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static int phx_acp_deinit(void __iomem *base) |
| +{ |
| + int ret = 0; |
| + |
| + /* Reset */ |
| + ret = acp6x_reset(base); |
| + if (ret) { |
| + pr_err("ACP reset failed\n"); |
| + return ret; |
| + } |
| + |
| + writel(0x00, base + ACP_CONTROL); |
| + |
| + /* power off */ |
| + ret = acp6x_power_off(base); |
| + if (ret) { |
| + pr_err("ACP power off failed\n"); |
| + return ret; |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +static int phoenix_audio_probe(struct platform_device *pdev) |
| +{ |
| + struct device *dev = &pdev->dev; |
| + struct acp_chip_info *chip; |
| + struct acp_dev_data *adata; |
| + struct resource *res; |
| + |
| + chip = dev_get_platdata(&pdev->dev); |
| + if (!chip || !chip->base) { |
| + dev_err(&pdev->dev, "ACP chip data is NULL\n"); |
| + return -ENODEV; |
| + } |
| + |
| + if (chip->acp_rev != ACP63X_DEV) { |
| + dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); |
| + return -ENODEV; |
| + } |
| + |
| + phx_acp_init(chip->base); |
| + |
| + adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL); |
| + if (!adata) |
| + return -ENOMEM; |
| + |
| + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem"); |
| + if (!res) { |
| + dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); |
| + return -ENODEV; |
| + } |
| + |
| + adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); |
| + if (!adata->acp_base) |
| + return -ENOMEM; |
| + |
| + res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq"); |
| + if (!res) { |
| + dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); |
| + return -ENODEV; |
| + } |
| + |
| + adata->i2s_irq = res->start; |
| + adata->dev = dev; |
| + adata->dai_driver = acp_phx_dai; |
| + adata->num_dai = ARRAY_SIZE(acp_phx_dai); |
| + adata->rsrc = &rsrc; |
| + |
| + adata->machines = snd_soc_acpi_amd_phx_acp_machines; |
| + acp_machine_select(adata); |
| + |
| + dev_set_drvdata(dev, adata); |
| + acp6x_enable_interrupts(adata); |
| + acp_platform_register(dev); |
| + |
| + return 0; |
| +} |
| + |
| +static void phoenix_audio_remove(struct platform_device *pdev) |
| +{ |
| + struct device *dev = &pdev->dev; |
| + struct acp_dev_data *adata = dev_get_drvdata(dev); |
| + struct acp_chip_info *chip = dev_get_platdata(dev); |
| + |
| + phx_acp_deinit(chip->base); |
| + |
| + acp6x_disable_interrupts(adata); |
| + acp_platform_unregister(dev); |
| +} |
| + |
| +static struct platform_driver phoenix_driver = { |
| + .probe = phoenix_audio_probe, |
| + .remove_new = phoenix_audio_remove, |
| + .driver = { |
| + .name = "acp_asoc_phoenix", |
| + }, |
| +}; |
| + |
| +module_platform_driver(phoenix_driver); |
| + |
| +MODULE_DESCRIPTION("AMD ACP Phoenix Driver"); |
| +MODULE_IMPORT_NS(SND_SOC_ACP_COMMON); |
| +MODULE_LICENSE("Dual BSD/GPL"); |
| +MODULE_ALIAS("platform:" DRV_NAME); |
| diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h |
| index d6cfae6ec5f74a472501011d8e3ab3974775b626..6592fadd8c8d8b321a12a3804c988e9018296038 100644 |
| --- a/sound/soc/amd/acp/amd.h |
| +++ b/sound/soc/amd/acp/amd.h |
| @@ -20,6 +20,7 @@ |
| |
| #define ACP3X_DEV 3 |
| #define ACP6X_DEV 6 |
| +#define ACP63X_DEV 63 |
| |
| #define DMIC_INSTANCE 0x00 |
| #define I2S_SP_INSTANCE 0x01 |
| @@ -188,9 +189,9 @@ union acp_i2stdm_mstrclkgen { |
| struct { |
| u32 i2stdm_master_mode : 1; |
| u32 i2stdm_format_mode : 1; |
| - u32 i2stdm_lrclk_div_val : 9; |
| + u32 i2stdm_lrclk_div_val : 11; |
| u32 i2stdm_bclk_div_val : 11; |
| - u32:10; |
| + u32:8; |
| } bitfields, bits; |
| u32 u32_all; |
| }; |
| -- |
| 2.34.1 |
| |