blob: bce7f01defec5eef880aeb1ea20ccbf8729a05b0 [file] [log] [blame]
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 = &amp_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