diff options
Diffstat (limited to 'sound/soc/amd')
32 files changed, 1888 insertions, 148 deletions
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 1381aec23048..08f5289dac54 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -23,6 +23,18 @@ config SND_SOC_AMD_CZ_RT5645_MACH help This option enables machine driver for rt5645. +config SND_SOC_AMD_ST_ES8336_MACH + tristate "AMD ST support for ES8336" + select SND_SOC_ACPI if ACPI + select SND_SOC_ES8316 + depends on SND_SOC_AMD_ACP && ACPI + depends on I2C + help + This option enables machine driver for Jadeite platform + using es8336 codec. + Say m if you have such a device. + If unsure select "N". + config SND_SOC_AMD_ACP3x tristate "AMD Audio Coprocessor-v3.x support" depends on X86 && PCI @@ -105,3 +117,13 @@ config SND_AMD_ACP_CONFIG driver modules to use source "sound/soc/amd/acp/Kconfig" + +config SND_SOC_AMD_RPL_ACP6x + tristate "AMD Audio Coprocessor-v6.2 RPL support" + depends on X86 && PCI + help + This option enables Audio Coprocessor i.e ACP v6.2 support on + AMD RPL platform. By enabling this flag build will be + triggered for ACP PCI driver. + Say m if you have such a device. + If unsure select "N". diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile index 4b1f77930a4a..0592e7c5c407 100644 --- a/sound/soc/amd/Makefile +++ b/sound/soc/amd/Makefile @@ -2,12 +2,14 @@ acp_audio_dma-objs := acp-pcm-dma.o snd-soc-acp-da7219mx98357-mach-objs := acp-da7219-max98357a.o snd-soc-acp-rt5645-mach-objs := acp-rt5645.o +snd-soc-acp-es8336-mach-objs := acp-es8336.o snd-soc-acp-rt5682-mach-objs := acp3x-rt5682-max9836.o snd-acp-config-objs := acp-config.o obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o obj-$(CONFIG_SND_SOC_AMD_CZ_DA7219MX98357_MACH) += snd-soc-acp-da7219mx98357-mach.o obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o +obj-$(CONFIG_SND_SOC_AMD_ST_ES8336_MACH) += snd-soc-acp-es8336-mach.o obj-$(CONFIG_SND_SOC_AMD_ACP3x) += raven/ obj-$(CONFIG_SND_SOC_AMD_RV_RT5682_MACH) += snd-soc-acp-rt5682-mach.o obj-$(CONFIG_SND_SOC_AMD_RENOIR) += renoir/ @@ -15,3 +17,4 @@ obj-$(CONFIG_SND_SOC_AMD_ACP5x) += vangogh/ obj-$(CONFIG_SND_SOC_AMD_ACP6x) += yc/ obj-$(CONFIG_SND_SOC_AMD_ACP_COMMON) += acp/ obj-$(CONFIG_SND_AMD_ACP_CONFIG) += snd-acp-config.o +obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += rpl/ diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c index 5cbc82eca4c9..0932473b6394 100644 --- a/sound/soc/amd/acp-config.c +++ b/sound/soc/amd/acp-config.c @@ -130,4 +130,34 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[] = { }; EXPORT_SYMBOL(snd_soc_acpi_amd_sof_machines); +struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[] = { + { + .id = "AMDI1019", + .drv_name = "rmb-dsp", + .pdata = &acp_quirk_data, + .fw_filename = "sof-rmb.ri", + .sof_tplg_filename = "sof-acp-rmb.tplg", + }, + { + .id = "10508825", + .drv_name = "nau8825-max", + .pdata = &acp_quirk_data, + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_max, + .fw_filename = "sof-rmb.ri", + .sof_tplg_filename = "sof-rmb-nau8825-max98360.tplg", + }, + { + .id = "RTL5682", + .drv_name = "rt5682s-hs-rt1019", + .pdata = &acp_quirk_data, + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_rt1019, + .fw_filename = "sof-rmb.ri", + .sof_tplg_filename = "sof-rmb-rt5682s-rt1019.tplg", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_rmb_sof_machines); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/acp-es8336.c b/sound/soc/amd/acp-es8336.c new file mode 100644 index 000000000000..2fe8df86053a --- /dev/null +++ b/sound/soc/amd/acp-es8336.c @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Machine driver for AMD Stoney platform using ES8336 Codec + * + * Copyright 2022 Advanced Micro Devices, Inc. + */ + +#include <sound/core.h> +#include <sound/soc.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc-dapm.h> +#include <sound/jack.h> +#include <linux/gpio.h> +#include <linux/device.h> +#include <linux/dmi.h> +#include <linux/gpio/consumer.h> +#include <linux/gpio/machine.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/acpi.h> + +#include "acp.h" + +#define DUAL_CHANNEL 2 +#define DRV_NAME "acp2x_mach" +#define ST_JADEITE 1 +#define ES8336_PLL_FREQ (48000 * 256) + +static unsigned long acp2x_machine_id; +static struct snd_soc_jack st_jack; +static struct device *codec_dev; +static struct gpio_desc *gpio_pa; + +static int sof_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + gpiod_set_value_cansleep(gpio_pa, true); + else + gpiod_set_value_cansleep(gpio_pa, false); + + return 0; +} + +static struct snd_soc_jack_pin st_es8316_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int st_es8336_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct snd_soc_card *card; + struct snd_soc_component *codec; + + codec = asoc_rtd_to_codec(rtd, 0)->component; + card = rtd->card; + + ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, + &st_jack, st_es8316_jack_pins, + ARRAY_SIZE(st_es8316_jack_pins)); + if (ret) { + dev_err(card->dev, "HP jack creation failed %d\n", ret); + return ret; + } + snd_jack_set_key(st_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + ret = snd_soc_component_set_jack(codec, &st_jack, NULL); + if (ret) { + dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); + return ret; + } + return 0; +} + +static const unsigned int st_channels[] = { + DUAL_CHANNEL, +}; + +static const unsigned int st_rates[] = { + 48000, +}; + +static const struct snd_pcm_hw_constraint_list st_constraints_rates = { + .count = ARRAY_SIZE(st_rates), + .list = st_rates, + .mask = 0, +}; + +static const struct snd_pcm_hw_constraint_list st_constraints_channels = { + .count = ARRAY_SIZE(st_channels), + .list = st_channels, + .mask = 0, +}; + +static int st_es8336_codec_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_card *card; + struct acp_platform_info *machine; + struct snd_soc_dai *codec_dai; + int ret; + + runtime = substream->runtime; + rtd = asoc_substream_to_rtd(substream); + card = rtd->card; + machine = snd_soc_card_get_drvdata(card); + codec_dai = asoc_rtd_to_codec(rtd, 0); + ret = snd_soc_dai_set_sysclk(codec_dai, 0, ES8336_PLL_FREQ, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret); + return ret; + } + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &st_constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &st_constraints_rates); + + machine->play_i2s_instance = I2S_MICSP_INSTANCE; + machine->cap_i2s_instance = I2S_MICSP_INSTANCE; + machine->capture_channel = CAP_CHANNEL0; + return 0; +} + +static const struct snd_soc_ops st_es8336_ops = { + .startup = st_es8336_codec_startup, +}; + +SND_SOC_DAILINK_DEF(designware1, + DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.2.auto"))); +SND_SOC_DAILINK_DEF(codec, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8336:00", "ES8316 HiFi"))); +SND_SOC_DAILINK_DEF(platform, + DAILINK_COMP_ARRAY(COMP_PLATFORM("acp_audio_dma.1.auto"))); + +static struct snd_soc_dai_link st_dai_es8336[] = { + { + .name = "amdes8336", + .stream_name = "ES8336 HiFi Play", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBP_CFP, + .stop_dma_first = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .init = st_es8336_init, + .ops = &st_es8336_ops, + SND_SOC_DAILINK_REG(designware1, codec, platform), + }, +}; + +static const struct snd_soc_dapm_widget st_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Internal Mic", NULL), + + SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, + sof_es8316_speaker_power_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), +}; + +static const struct snd_soc_dapm_route st_audio_route[] = { + {"Speaker", NULL, "HPOL"}, + {"Speaker", NULL, "HPOR"}, + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + {"MIC1", NULL, "Headset Mic"}, + {"MIC2", NULL, "Internal Mic"}, + {"Speaker", NULL, "Speaker Power"}, +}; + +static const struct snd_kcontrol_new st_mc_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Internal Mic"), +}; + +static const struct acpi_gpio_params pa_enable_gpio = { 0, 0, false }; +static const struct acpi_gpio_mapping acpi_es8336_gpios[] = { + { "pa-enable-gpios", &pa_enable_gpio, 1 }, + { } +}; + +static int st_es8336_late_probe(struct snd_soc_card *card) +{ + struct acpi_device *adev; + int ret; + + adev = acpi_dev_get_first_match_dev("ESSX8336", NULL, -1); + if (adev) + put_device(&adev->dev); + codec_dev = acpi_get_first_physical_node(adev); + if (!codec_dev) + dev_err(card->dev, "can not find codec dev\n"); + + ret = devm_acpi_dev_add_driver_gpios(codec_dev, acpi_es8336_gpios); + if (ret) + dev_warn(card->dev, "Failed to add driver gpios\n"); + + gpio_pa = gpiod_get_optional(codec_dev, "pa-enable", GPIOD_OUT_LOW); + if (IS_ERR(gpio_pa)) { + ret = dev_err_probe(card->dev, PTR_ERR(gpio_pa), + "could not get pa-enable GPIO\n"); + put_device(codec_dev); + return ret; + } + return 0; +} + +static struct snd_soc_card st_card = { + .name = "acpes8336", + .owner = THIS_MODULE, + .dai_link = st_dai_es8336, + .num_links = ARRAY_SIZE(st_dai_es8336), + .dapm_widgets = st_widgets, + .num_dapm_widgets = ARRAY_SIZE(st_widgets), + .dapm_routes = st_audio_route, + .num_dapm_routes = ARRAY_SIZE(st_audio_route), + .controls = st_mc_controls, + .num_controls = ARRAY_SIZE(st_mc_controls), + .late_probe = st_es8336_late_probe, +}; + +static int st_es8336_quirk_cb(const struct dmi_system_id *id) +{ + acp2x_machine_id = ST_JADEITE; + return 1; +} + +static const struct dmi_system_id st_es8336_quirk_table[] = { + { + .callback = st_es8336_quirk_cb, + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMD"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jadeite"), + }, + }, + { + .callback = st_es8336_quirk_cb, + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "IP3 Technology CO.,Ltd."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ASN1D"), + }, + }, + { + .callback = st_es8336_quirk_cb, + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Standard"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ASN10"), + }, + }, + {} +}; + +static int st_es8336_probe(struct platform_device *pdev) +{ + int ret; + struct snd_soc_card *card; + struct acp_platform_info *machine; + + machine = devm_kzalloc(&pdev->dev, sizeof(struct acp_platform_info), GFP_KERNEL); + if (!machine) + return -ENOMEM; + + dmi_check_system(st_es8336_quirk_table); + switch (acp2x_machine_id) { + case ST_JADEITE: + card = &st_card; + st_card.dev = &pdev->dev; + break; + default: + return -ENODEV; + } + + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, machine); + ret = devm_snd_soc_register_card(&pdev->dev, &st_card); + if (ret) { + return dev_err_probe(&pdev->dev, ret, + "devm_snd_soc_register_card(%s) failed\n", + card->name); + } + return 0; +} + +#ifdef CONFIG_ACPI +static const struct acpi_device_id st_audio_acpi_match[] = { + {"AMDI8336", 0}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, st_audio_acpi_match); +#endif + +static struct platform_driver st_mach_driver = { + .driver = { + .name = "st-es8316", + .acpi_match_table = ACPI_PTR(st_audio_acpi_match), + .pm = &snd_soc_pm_ops, + }, + .probe = st_es8336_probe, +}; + +module_platform_driver(st_mach_driver); + +MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); +MODULE_DESCRIPTION("st-es8316 audio support"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index 1cd2e70a57df..198358d28ea9 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -433,6 +433,7 @@ static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num, bool is_circular) case I2S_TO_ACP_DMA_CH_NUM: case ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM: case I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM: + case ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM: dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK; break; default: @@ -710,6 +711,13 @@ static irqreturn_t dma_irq_handler(int irq, void *arg) acp_mmio, mmACP_EXTERNAL_INTR_STAT); } + if ((intr_flag & BIT(ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM)) != 0) { + valid_irq = true; + snd_pcm_period_elapsed(irq_data->play_i2s_micsp_stream); + acp_reg_write((intr_flag & BIT(ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM)) << 16, + acp_mmio, mmACP_EXTERNAL_INTR_STAT); + } + if ((intr_flag & BIT(ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM)) != 0) { valid_irq = true; snd_pcm_period_elapsed(irq_data->play_i2sbt_stream); @@ -807,7 +815,8 @@ static int acp_dma_open(struct snd_soc_component *component, * stream is not closed */ if (!intr_data->play_i2ssp_stream && !intr_data->capture_i2ssp_stream && - !intr_data->play_i2sbt_stream && !intr_data->capture_i2sbt_stream) + !intr_data->play_i2sbt_stream && !intr_data->capture_i2sbt_stream && + !intr_data->play_i2s_micsp_stream) acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -867,6 +876,9 @@ static int acp_dma_hw_params(struct snd_soc_component *component, case I2S_BT_INSTANCE: val |= ACP_I2S_BT_16BIT_RESOLUTION_EN; break; + case I2S_MICSP_INSTANCE: + val |= ACP_I2S_MICSP_16BIT_RESOLUTION_EN; + break; case I2S_SP_INSTANCE: default: val |= ACP_I2S_SP_16BIT_RESOLUTION_EN; @@ -876,6 +888,7 @@ static int acp_dma_hw_params(struct snd_soc_component *component, case I2S_BT_INSTANCE: val |= ACP_I2S_BT_16BIT_RESOLUTION_EN; break; + case I2S_MICSP_INSTANCE: case I2S_SP_INSTANCE: default: val |= ACP_I2S_MIC_16BIT_RESOLUTION_EN; @@ -901,6 +914,27 @@ static int acp_dma_hw_params(struct snd_soc_component *component, mmACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW; adata->play_i2sbt_stream = substream; break; + case I2S_MICSP_INSTANCE: + switch (adata->asic_type) { + case CHIP_STONEY: + rtd->pte_offset = ACP_ST_PLAYBACK_PTE_OFFSET; + break; + default: + rtd->pte_offset = ACP_PLAYBACK_PTE_OFFSET; + } + rtd->ch1 = SYSRAM_TO_ACP_MICSP_INSTANCE_CH_NUM; + rtd->ch2 = ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM; + rtd->sram_bank = ACP_SRAM_BANK_1_ADDRESS; + rtd->destination = TO_ACP_I2S_2; + rtd->dma_dscr_idx_1 = PLAYBACK_START_DMA_DESCR_CH4; + rtd->dma_dscr_idx_2 = PLAYBACK_START_DMA_DESCR_CH5; + rtd->byte_cnt_high_reg_offset = + mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH; + rtd->byte_cnt_low_reg_offset = + mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW; + + adata->play_i2s_micsp_stream = substream; + break; case I2S_SP_INSTANCE: default: switch (adata->asic_type) { @@ -939,6 +973,7 @@ static int acp_dma_hw_params(struct snd_soc_component *component, rtd->dma_curr_dscr = mmACP_DMA_CUR_DSCR_11; adata->capture_i2sbt_stream = substream; break; + case I2S_MICSP_INSTANCE: case I2S_SP_INSTANCE: default: rtd->pte_offset = ACP_CAPTURE_PTE_OFFSET; @@ -1160,6 +1195,9 @@ static int acp_dma_close(struct snd_soc_component *component, case I2S_BT_INSTANCE: adata->play_i2sbt_stream = NULL; break; + case I2S_MICSP_INSTANCE: + adata->play_i2s_micsp_stream = NULL; + break; case I2S_SP_INSTANCE: default: adata->play_i2ssp_stream = NULL; @@ -1181,6 +1219,7 @@ static int acp_dma_close(struct snd_soc_component *component, case I2S_BT_INSTANCE: adata->capture_i2sbt_stream = NULL; break; + case I2S_MICSP_INSTANCE: case I2S_SP_INSTANCE: default: adata->capture_i2ssp_stream = NULL; @@ -1197,7 +1236,8 @@ static int acp_dma_close(struct snd_soc_component *component, * another stream is also not active. */ if (!adata->play_i2ssp_stream && !adata->capture_i2ssp_stream && - !adata->play_i2sbt_stream && !adata->capture_i2sbt_stream) + !adata->play_i2sbt_stream && !adata->capture_i2sbt_stream && + !adata->play_i2s_micsp_stream) acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); kfree(rtd); return 0; @@ -1245,6 +1285,7 @@ static int acp_audio_probe(struct platform_device *pdev) audio_drv_data->capture_i2ssp_stream = NULL; audio_drv_data->play_i2sbt_stream = NULL; audio_drv_data->capture_i2sbt_stream = NULL; + audio_drv_data->play_i2s_micsp_stream = NULL; audio_drv_data->asic_type = *pdata; @@ -1333,6 +1374,11 @@ static int acp_pcm_resume(struct device *dev) config_acp_dma(adata->acp_mmio, rtd, adata->asic_type); } if (adata->asic_type != CHIP_CARRIZO) { + if (adata->play_i2s_micsp_stream && + adata->play_i2s_micsp_stream->runtime) { + rtd = adata->play_i2s_micsp_stream->runtime->private_data; + config_acp_dma(adata->acp_mmio, rtd, adata->asic_type); + } if (adata->play_i2sbt_stream && adata->play_i2sbt_stream->runtime) { rtd = adata->play_i2sbt_stream->runtime->private_data; diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h index db80a73aa593..b29bef90f886 100644 --- a/sound/soc/amd/acp.h +++ b/sound/soc/amd/acp.h @@ -55,6 +55,7 @@ #define I2S_SP_INSTANCE 0x01 #define I2S_BT_INSTANCE 0x02 +#define I2S_MICSP_INSTANCE 0x03 #define CAP_CHANNEL0 0x00 #define CAP_CHANNEL1 0x01 @@ -85,6 +86,10 @@ #define I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM 10 #define ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM 11 +/* Playback DMA channels for I2S MICSP instance */ +#define SYSRAM_TO_ACP_MICSP_INSTANCE_CH_NUM 4 +#define ACP_TO_I2S_DMA_MICSP_INSTANCE_CH_NUM 5 + #define NUM_DSCRS_PER_CHANNEL 2 #define PLAYBACK_START_DMA_DESCR_CH12 0 @@ -108,8 +113,15 @@ #define CAPTURE_START_DMA_DESCR_CH11 14 #define CAPTURE_END_DMA_DESCR_CH11 15 +/* I2S MICSP Instance DMA Descriptors */ +#define PLAYBACK_START_DMA_DESCR_CH4 0 +#define PLAYBACK_END_DMA_DESCR_CH4 1 +#define PLAYBACK_START_DMA_DESCR_CH5 2 +#define PLAYBACK_END_DMA_DESCR_CH5 3 + #define mmACP_I2S_16BIT_RESOLUTION_EN 0x5209 #define ACP_I2S_MIC_16BIT_RESOLUTION_EN 0x01 +#define ACP_I2S_MICSP_16BIT_RESOLUTION_EN 0x01 #define ACP_I2S_SP_16BIT_RESOLUTION_EN 0x02 #define ACP_I2S_BT_16BIT_RESOLUTION_EN 0x04 #define ACP_BT_UART_PAD_SELECT_MASK 0x1 @@ -149,6 +161,7 @@ struct audio_drv_data { struct snd_pcm_substream *capture_i2ssp_stream; struct snd_pcm_substream *play_i2sbt_stream; struct snd_pcm_substream *capture_i2sbt_stream; + struct snd_pcm_substream *play_i2s_micsp_stream; void __iomem *acp_mmio; u32 asic_type; snd_pcm_sframes_t delay; diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index 9dae2719084c..ce0037810743 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -40,6 +40,17 @@ config SND_AMD_ASOC_RENOIR help This option enables Renoir I2S support on AMD platform. +config SND_AMD_ASOC_REMBRANDT + tristate "AMD ACP ASOC Rembrandt 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 Rembrandt I2S support on AMD platform. + Say Y if you want to enable AUDIO on Rembrandt + If unsure select "N". + config SND_SOC_AMD_MACH_COMMON tristate depends on X86 && PCI && I2C @@ -49,6 +60,7 @@ config SND_SOC_AMD_MACH_COMMON select SND_SOC_RT1019 select SND_SOC_MAX98357A select SND_SOC_RT5682S + select SND_SOC_NAU8825 help This option enables common Machine driver module for ACP. diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile index 657ddfadf0bb..d9abb0ee5218 100644 --- a/sound/soc/amd/acp/Makefile +++ b/sound/soc/amd/acp/Makefile @@ -12,6 +12,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 #machine specific driver snd-acp-mach-objs := acp-mach-common.o @@ -24,6 +25,7 @@ obj-$(CONFIG_SND_SOC_AMD_ACP_PDM) += snd-acp-pdm.o 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_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-i2s.c b/sound/soc/amd/acp/acp-i2s.c index ce9aca8dd6f5..393f729ef561 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -30,11 +30,14 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ { struct device *dev = dai->component->dev; struct acp_dev_data *adata; + struct acp_resource *rsrc; u32 val; u32 xfer_resolution; u32 reg_val; + u32 lrclk_div_val, bclk_div_val; adata = snd_soc_dai_get_drvdata(dai); + rsrc = adata->rsrc; /* These values are as per Hardware Spec */ switch (params_format(params)) { @@ -63,6 +66,9 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ case I2S_SP_INSTANCE: reg_val = ACP_I2STDM_ITER; break; + case I2S_HS_INSTANCE: + reg_val = ACP_HSTDM_ITER; + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -75,6 +81,9 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ case I2S_SP_INSTANCE: reg_val = ACP_I2STDM_IRER; break; + case I2S_HS_INSTANCE: + reg_val = ACP_HSTDM_IRER; + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -86,6 +95,74 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ val = val | (xfer_resolution << 3); writel(val, adata->acp_base + reg_val); + if (rsrc->soc_mclk) { + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + switch (params_rate(params)) { + case 8000: + bclk_div_val = 768; + break; + case 16000: + bclk_div_val = 384; + break; + case 24000: + bclk_div_val = 256; + break; + case 32000: + bclk_div_val = 192; + break; + case 44100: + case 48000: + bclk_div_val = 128; + break; + case 88200: + case 96000: + bclk_div_val = 64; + break; + case 192000: + bclk_div_val = 32; + break; + default: + return -EINVAL; + } + lrclk_div_val = 32; + break; + case SNDRV_PCM_FORMAT_S32_LE: + switch (params_rate(params)) { + case 8000: + bclk_div_val = 384; + break; + case 16000: + bclk_div_val = 192; + break; + case 24000: + bclk_div_val = 128; + break; + case 32000: + bclk_div_val = 96; + break; + case 44100: + case 48000: + bclk_div_val = 64; + break; + case 88200: + case 96000: + bclk_div_val = 32; + break; + case 192000: + bclk_div_val = 16; + break; + default: + return -EINVAL; + } + lrclk_div_val = 64; + break; + default: + return -EINVAL; + } + adata->lrclk_div = lrclk_div_val; + adata->bclk_div = bclk_div_val; + } return 0; } @@ -94,6 +171,7 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct struct acp_stream *stream = substream->runtime->private_data; struct device *dev = dai->component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_resource *rsrc = adata->rsrc; u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg; period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size); @@ -118,6 +196,12 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct ier_val = ACP_I2STDM_IER; buf_reg = ACP_I2S_TX_RINGBUFSIZE; break; + case I2S_HS_INSTANCE: + water_val = ACP_HS_TX_INTR_WATERMARK_SIZE; + reg_val = ACP_HSTDM_ITER; + ier_val = ACP_HSTDM_IER; + buf_reg = ACP_HS_TX_RINGBUFSIZE; + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -136,6 +220,12 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct ier_val = ACP_I2STDM_IER; buf_reg = ACP_I2S_RX_RINGBUFSIZE; break; + case I2S_HS_INSTANCE: + water_val = ACP_HS_RX_INTR_WATERMARK_SIZE; + reg_val = ACP_HSTDM_IRER; + ier_val = ACP_HSTDM_IER; + buf_reg = ACP_HS_RX_RINGBUFSIZE; + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -147,6 +237,8 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct val = val | BIT(0); writel(val, adata->acp_base + reg_val); writel(1, adata->acp_base + ier_val); + if (rsrc->soc_mclk) + acp_set_i2s_clk(adata, dai->driver->id); return 0; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: @@ -159,6 +251,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct case I2S_SP_INSTANCE: reg_val = ACP_I2STDM_ITER; break; + case I2S_HS_INSTANCE: + reg_val = ACP_HSTDM_ITER; + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -172,6 +267,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct case I2S_SP_INSTANCE: reg_val = ACP_I2STDM_IRER; break; + case I2S_HS_INSTANCE: + reg_val = ACP_HSTDM_IRER; + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -187,6 +285,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct if (!(readl(adata->acp_base + ACP_I2STDM_ITER) & BIT(0)) && !(readl(adata->acp_base + ACP_I2STDM_IRER) & BIT(0))) writel(0, adata->acp_base + ACP_I2STDM_IER); + if (!(readl(adata->acp_base + ACP_HSTDM_ITER) & BIT(0)) && + !(readl(adata->acp_base + ACP_HSTDM_IRER) & BIT(0))) + writel(0, adata->acp_base + ACP_HSTDM_IER); return 0; default: return -EINVAL; @@ -199,6 +300,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d { struct device *dev = dai->component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_resource *rsrc = adata->rsrc; struct acp_stream *stream = substream->runtime->private_data; u32 reg_dma_size = 0, reg_fifo_size = 0, reg_fifo_addr = 0; u32 phy_addr = 0, acp_fifo_addr = 0, ext_int_ctrl; @@ -208,7 +310,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d case I2S_SP_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { reg_dma_size = ACP_I2S_TX_DMA_SIZE; - acp_fifo_addr = ACP_SRAM_PTE_OFFSET + + acp_fifo_addr = rsrc->sram_pte_offset + SP_PB_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_I2S_TX_FIFOADDR; reg_fifo_size = ACP_I2S_TX_FIFOSIZE; @@ -217,7 +319,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR); } else { reg_dma_size = ACP_I2S_RX_DMA_SIZE; - acp_fifo_addr = ACP_SRAM_PTE_OFFSET + + acp_fifo_addr = rsrc->sram_pte_offset + SP_CAPT_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_I2S_RX_FIFOADDR; reg_fifo_size = ACP_I2S_RX_FIFOSIZE; @@ -228,7 +330,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d case I2S_BT_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { reg_dma_size = ACP_BT_TX_DMA_SIZE; - acp_fifo_addr = ACP_SRAM_PTE_OFFSET + + acp_fifo_addr = rsrc->sram_pte_offset + BT_PB_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_BT_TX_FIFOADDR; reg_fifo_size = ACP_BT_TX_FIFOSIZE; @@ -237,7 +339,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR); } else { reg_dma_size = ACP_BT_RX_DMA_SIZE; - acp_fifo_addr = ACP_SRAM_PTE_OFFSET + + acp_fifo_addr = rsrc->sram_pte_offset + BT_CAPT_FIFO_ADDR_OFFSET; reg_fifo_addr = ACP_BT_RX_FIFOADDR; reg_fifo_size = ACP_BT_RX_FIFOSIZE; @@ -246,6 +348,27 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR); } break; + case I2S_HS_INSTANCE: + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + reg_dma_size = ACP_HS_TX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + HS_PB_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_HS_TX_FIFOADDR; + reg_fifo_size = ACP_HS_TX_FIFOSIZE; + + phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR); + } else { + reg_dma_size = ACP_HS_RX_DMA_SIZE; + acp_fifo_addr = rsrc->sram_pte_offset + + HS_CAPT_FIFO_ADDR_OFFSET; + reg_fifo_addr = ACP_HS_RX_FIFOADDR; + reg_fifo_size = ACP_HS_RX_FIFOSIZE; + + phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; + writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR); + } + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -255,11 +378,15 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr); writel(FIFO_SIZE, adata->acp_base + reg_fifo_size); - ext_int_ctrl = readl(adata->acp_base + ACP_EXTERNAL_INTR_CNTL); - ext_int_ctrl |= BIT(I2S_RX_THRESHOLD) | BIT(BT_RX_THRESHOLD) - | BIT(I2S_TX_THRESHOLD) | BIT(BT_TX_THRESHOLD); + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); + ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) | + BIT(BT_RX_THRESHOLD(rsrc->offset)) | + BIT(I2S_TX_THRESHOLD(rsrc->offset)) | + BIT(BT_TX_THRESHOLD(rsrc->offset)) | + BIT(HS_RX_THRESHOLD(rsrc->offset)) | + BIT(HS_TX_THRESHOLD(rsrc->offset)); - writel(ext_int_ctrl, adata->acp_base + ACP_EXTERNAL_INTR_CNTL); + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); return 0; } @@ -268,32 +395,45 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d { struct acp_stream *stream = substream->runtime->private_data; struct device *dev = dai->component->dev; + struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_resource *rsrc = adata->rsrc; unsigned int dir = substream->stream; unsigned int irq_bit = 0; switch (dai->driver->id) { case I2S_SP_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - irq_bit = BIT(I2S_TX_THRESHOLD); + irq_bit = BIT(I2S_TX_THRESHOLD(rsrc->offset)); stream->pte_offset = ACP_SRAM_SP_PB_PTE_OFFSET; stream->fifo_offset = SP_PB_FIFO_ADDR_OFFSET; } else { - irq_bit = BIT(I2S_RX_THRESHOLD); + irq_bit = BIT(I2S_RX_THRESHOLD(rsrc->offset)); stream->pte_offset = ACP_SRAM_SP_CP_PTE_OFFSET; stream->fifo_offset = SP_CAPT_FIFO_ADDR_OFFSET; } break; case I2S_BT_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - irq_bit = BIT(BT_TX_THRESHOLD); + irq_bit = BIT(BT_TX_THRESHOLD(rsrc->offset)); stream->pte_offset = ACP_SRAM_BT_PB_PTE_OFFSET; stream->fifo_offset = BT_PB_FIFO_ADDR_OFFSET; } else { - irq_bit = BIT(BT_RX_THRESHOLD); + irq_bit = BIT(BT_RX_THRESHOLD(rsrc->offset)); stream->pte_offset = ACP_SRAM_BT_CP_PTE_OFFSET; stream->fifo_offset = BT_CAPT_FIFO_ADDR_OFFSET; } break; + case I2S_HS_INSTANCE: + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + irq_bit = BIT(HS_TX_THRESHOLD(rsrc->offset)); + stream->pte_offset = ACP_SRAM_HS_PB_PTE_OFFSET; + stream->fifo_offset = HS_PB_FIFO_ADDR_OFFSET; + } else { + irq_bit = BIT(HS_RX_THRESHOLD(rsrc->offset)); + stream->pte_offset = ACP_SRAM_HS_CP_PTE_OFFSET; + stream->fifo_offset = HS_CAPT_FIFO_ADDR_OFFSET; + } + break; default: dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; @@ -319,6 +459,7 @@ int asoc_acp_i2s_probe(struct snd_soc_dai *dai) { struct device *dev = dai->component->dev; struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_resource *rsrc = adata->rsrc; unsigned int val; if (!adata->acp_base) { @@ -326,8 +467,8 @@ int asoc_acp_i2s_probe(struct snd_soc_dai *dai) return -EINVAL; } - val = readl(adata->acp_base + ACP_I2S_PIN_CONFIG); - if (val != I2S_MODE) { + val = readl(adata->acp_base + rsrc->i2s_pin_cfg_offset); + if (val != rsrc->i2s_mode) { dev_err(dev, "I2S Mode not supported val %x\n", val); return -EINVAL; } diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c index 7f04a048ca3a..1f4878ff7d37 100644 --- a/sound/soc/amd/acp/acp-legacy-mach.c +++ b/sound/soc/amd/acp/acp-legacy-mach.c @@ -47,6 +47,28 @@ static struct acp_card_drvdata rt5682s_rt1019_data = { .dmic_codec_id = DMIC, }; +static struct acp_card_drvdata max_nau8825_data = { + .hs_cpu_id = I2S_HS, + .amp_cpu_id = I2S_HS, + .dmic_cpu_id = DMIC, + .hs_codec_id = NAU8825, + .amp_codec_id = MAX98360A, + .dmic_codec_id = DMIC, + .soc_mclk = true, + .platform = REMBRANDT, +}; + +static struct acp_card_drvdata rt5682s_rt1019_rmb_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 = REMBRANDT, +}; + static const struct snd_kcontrol_new acp_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), @@ -112,6 +134,14 @@ static const struct platform_device_id board_ids[] = { .name = "acp3xalc5682s1019", .driver_data = (kernel_ulong_t)&rt5682s_rt1019_data, }, + { + .name = "rmb-nau8825-max", + .driver_data = (kernel_ulong_t)&max_nau8825_data, + }, + { + .name = "rmb-rt5682s-rt1019", + .driver_data = (kernel_ulong_t)&rt5682s_rt1019_rmb_data, + }, { } }; static struct platform_driver acp_asoc_audio = { @@ -130,4 +160,6 @@ MODULE_DESCRIPTION("ACP chrome audio support"); MODULE_ALIAS("platform:acp3xalc56821019"); MODULE_ALIAS("platform:acp3xalc5682sm98360"); MODULE_ALIAS("platform:acp3xalc5682s1019"); +MODULE_ALIAS("platform:rmb-nau8825-max"); +MODULE_ALIAS("platform:rmb-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 6ae454bf60af..f0c49127aad1 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -24,6 +24,7 @@ #include "../../codecs/rt5682.h" #include "../../codecs/rt1019.h" #include "../../codecs/rt5682s.h" +#include "../../codecs/nau8825.h" #include "acp-mach.h" #define PCO_PLAT_CLK 48000000 @@ -148,9 +149,14 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream) struct acp_card_drvdata *drvdata = card->drvdata; struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); int ret; + unsigned int fmt; - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBP_CFP); + if (drvdata->soc_mclk) + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + else + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP; + + ret = snd_soc_dai_set_fmt(codec_dai, fmt); if (ret < 0) { dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret); return ret; @@ -161,10 +167,13 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream) &constraints_channels); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - ret = acp_clk_enable(drvdata); - if (ret < 0) - dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret); + if (!drvdata->soc_mclk) { + ret = acp_clk_enable(drvdata); + if (ret < 0) { + dev_err(rtd->card->dev, "Failed to enable HS clk: %d\n", ret); + return ret; + } + } return ret; } @@ -175,7 +184,8 @@ static void acp_card_shutdown(struct snd_pcm_substream *substream) struct snd_soc_card *card = rtd->card; struct acp_card_drvdata *drvdata = card->drvdata; - clk_disable_unprepare(drvdata->wclk); + if (!drvdata->soc_mclk) + clk_disable_unprepare(drvdata->wclk); } static const struct snd_soc_ops acp_card_rt5682_ops = { @@ -199,6 +209,7 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd) struct acp_card_drvdata *drvdata = card->drvdata; struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct snd_soc_component *component = codec_dai->component; + unsigned int fmt; int ret; dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name); @@ -206,8 +217,12 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd) if (drvdata->hs_codec_id != RT5682S) return -EINVAL; - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBP_CFP); + if (drvdata->soc_mclk) + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + else + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP; + + ret = snd_soc_dai_set_fmt(codec_dai, fmt); if (ret < 0) { dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret); return ret; @@ -234,8 +249,10 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd) return ret; } - drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk"); - drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); + if (!drvdata->soc_mclk) { + drvdata->wclk = clk_get(component->dev, "rt5682-dai-wclk"); + drvdata->bclk = clk_get(component->dev, "rt5682-dai-bclk"); + } ret = snd_soc_card_jack_new(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_LINEOUT | @@ -363,7 +380,7 @@ static int acp_card_amp_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; struct acp_card_drvdata *drvdata = card->drvdata; - int ret; + int ret = 0; runtime->hw.channels_max = DUAL_CHANNEL; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, @@ -371,10 +388,13 @@ static int acp_card_amp_startup(struct snd_pcm_substream *substream) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - ret = acp_clk_enable(drvdata); - if (ret < 0) - dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret); - + if (!drvdata->soc_mclk) { + ret = acp_clk_enable(drvdata); + if (ret < 0) { + dev_err(rtd->card->dev, "Failed to enable AMP clk: %d\n", ret); + return ret; + } + } return ret; } @@ -409,6 +429,104 @@ static const struct snd_soc_ops acp_card_maxim_ops = { .shutdown = acp_card_shutdown, }; +/* Declare nau8825 codec components */ +SND_SOC_DAILINK_DEF(nau8825, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", "nau8825-hifi"))); + +static const struct snd_soc_dapm_route nau8825_map[] = { + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, +}; + +static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct acp_card_drvdata *drvdata = card->drvdata; + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + unsigned int fmt; + int ret; + + dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name); + + if (drvdata->hs_codec_id != NAU8825) + return -EINVAL; + + if (drvdata->soc_mclk) + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; + else + fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP; + + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) { + dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret); + return ret; + } + ret = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &pco_jack); + if (ret) { + dev_err(card->dev, "HP jack creation failed %d\n", ret); + return ret; + } + + snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + ret = snd_soc_component_set_jack(component, &pco_jack, NULL); + if (ret) { + dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); + return ret; + } + + return snd_soc_dapm_add_routes(&rtd->card->dapm, nau8825_map, ARRAY_SIZE(nau8825_map)); +} + +static int acp_nau8825_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS, + (48000 * 256), SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, params_rate(params), + params_rate(params) * 256); + if (ret < 0) { + dev_err(rtd->dev, "can't set FLL: %d\n", ret); + return ret; + } + + return ret; +} + +static int acp_nau8825_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = 2; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + return 0; +} + +static const struct snd_soc_ops acp_card_nau8825_ops = { + .startup = acp_nau8825_startup, + .hw_params = acp_nau8825_hw_params, +}; + /* Declare DMIC codec components */ SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); @@ -427,6 +545,12 @@ static struct snd_soc_dai_link_component platform_component[] = { } }; +static struct snd_soc_dai_link_component platform_rmb_component[] = { + { + .name = "acp_asoc_rembrandt.0", + } +}; + static struct snd_soc_dai_link_component sof_component[] = { { .name = "0000:04:00.5", @@ -435,8 +559,12 @@ static struct snd_soc_dai_link_component sof_component[] = { SND_SOC_DAILINK_DEF(i2s_sp, DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-sp"))); +SND_SOC_DAILINK_DEF(i2s_hs, + DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-hs"))); SND_SOC_DAILINK_DEF(sof_sp, DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp"))); +SND_SOC_DAILINK_DEF(sof_hs, + DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-hs"))); SND_SOC_DAILINK_DEF(sof_dmic, DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic"))); SND_SOC_DAILINK_DEF(pdm_dmic, @@ -491,6 +619,37 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) i++; } + if (drv_data->hs_cpu_id == I2S_HS) { + links[i].name = "acp-headset-codec"; + links[i].id = HEADSET_BE_ID; + links[i].cpus = sof_hs; + links[i].num_cpus = ARRAY_SIZE(sof_hs); + links[i].platforms = sof_component; + links[i].num_platforms = ARRAY_SIZE(sof_component); + links[i].dpcm_playback = 1; + links[i].dpcm_capture = 1; + links[i].nonatomic = true; + links[i].no_pcm = 1; + if (!drv_data->hs_codec_id) { + /* Use dummy codec if codec id not specified */ + links[i].codecs = dummy_codec; + links[i].num_codecs = ARRAY_SIZE(dummy_codec); + } + if (drv_data->hs_codec_id == NAU8825) { + links[i].codecs = nau8825; + links[i].num_codecs = ARRAY_SIZE(nau8825); + links[i].init = acp_card_nau8825_init; + links[i].ops = &acp_card_nau8825_ops; + } + if (drv_data->hs_codec_id == RT5682S) { + links[i].codecs = rt5682s; + links[i].num_codecs = ARRAY_SIZE(rt5682s); + links[i].init = acp_card_rt5682s_init; + links[i].ops = &acp_card_rt5682s_ops; + } + i++; + } + if (drv_data->amp_cpu_id == I2S_SP) { links[i].name = "acp-amp-codec"; links[i].id = AMP_BE_ID; @@ -523,6 +682,38 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) i++; } + if (drv_data->amp_cpu_id == I2S_HS) { + links[i].name = "acp-amp-codec"; + links[i].id = AMP_BE_ID; + links[i].cpus = sof_hs; + links[i].num_cpus = ARRAY_SIZE(sof_hs); + links[i].platforms = sof_component; + links[i].num_platforms = ARRAY_SIZE(sof_component); + links[i].dpcm_playback = 1; + links[i].nonatomic = true; + links[i].no_pcm = 1; + if (!drv_data->amp_codec_id) { + /* Use dummy codec if codec id not specified */ + links[i].codecs = dummy_codec; + links[i].num_codecs = ARRAY_SIZE(dummy_codec); + } + if (drv_data->amp_codec_id == MAX98360A) { + links[i].codecs = max98360a; + links[i].num_codecs = ARRAY_SIZE(max98360a); + links[i].ops = &acp_card_maxim_ops; + links[i].init = acp_card_maxim_init; + } + if (drv_data->amp_codec_id == RT1019) { + links[i].codecs = rt1019; + links[i].num_codecs = ARRAY_SIZE(rt1019); + links[i].ops = &acp_card_rt1019_ops; + links[i].init = acp_card_rt1019_init; + card->codec_conf = rt1019_conf; + card->num_configs = ARRAY_SIZE(rt1019_conf); + } + i++; + } + if (drv_data->dmic_cpu_id == DMIC) { links[i].name = "acp-dmic-codec"; links[i].id = DMIC_BE_ID; @@ -591,6 +782,40 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) i++; } + if (drv_data->hs_cpu_id == I2S_HS) { + links[i].name = "acp-headset-codec"; + links[i].id = HEADSET_BE_ID; + links[i].cpus = i2s_hs; + links[i].num_cpus = ARRAY_SIZE(i2s_hs); + if (drv_data->platform == REMBRANDT) { + links[i].platforms = platform_rmb_component; + links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); + } else { + links[i].platforms = platform_component; + links[i].num_platforms = ARRAY_SIZE(platform_component); + } + links[i].dpcm_playback = 1; + links[i].dpcm_capture = 1; + if (!drv_data->hs_codec_id) { + /* Use dummy codec if codec id not specified */ + links[i].codecs = dummy_codec; + links[i].num_codecs = ARRAY_SIZE(dummy_codec); + } + if (drv_data->hs_codec_id == NAU8825) { + links[i].codecs = nau8825; + links[i].num_codecs = ARRAY_SIZE(nau8825); + links[i].init = acp_card_nau8825_init; + links[i].ops = &acp_card_nau8825_ops; + } + if (drv_data->hs_codec_id == RT5682S) { + links[i].codecs = rt5682s; + links[i].num_codecs = ARRAY_SIZE(rt5682s); + links[i].init = acp_card_rt5682s_init; + links[i].ops = &acp_card_rt5682s_ops; + } + i++; + } + if (drv_data->amp_cpu_id == I2S_SP) { links[i].name = "acp-amp-codec"; links[i].id = AMP_BE_ID; @@ -621,6 +846,41 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) i++; } + if (drv_data->amp_cpu_id == I2S_HS) { + links[i].name = "acp-amp-codec"; + links[i].id = AMP_BE_ID; + links[i].cpus = i2s_hs; + links[i].num_cpus = ARRAY_SIZE(i2s_hs); + if (drv_data->platform == REMBRANDT) { + links[i].platforms = platform_rmb_component; + links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); + } else { + links[i].platforms = platform_component; + links[i].num_platforms = ARRAY_SIZE(platform_component); + } + links[i].dpcm_playback = 1; + if (!drv_data->amp_codec_id) { + /* Use dummy codec if codec id not specified */ + links[i].codecs = dummy_codec; + links[i].num_codecs = ARRAY_SIZE(dummy_codec); + } + if (drv_data->amp_codec_id == MAX98360A) { + links[i].codecs = max98360a; + links[i].num_codecs = ARRAY_SIZE(max98360a); + links[i].ops = &acp_card_maxim_ops; + links[i].init = acp_card_maxim_init; + } + if (drv_data->amp_codec_id == RT1019) { + links[i].codecs = rt1019; + links[i].num_codecs = ARRAY_SIZE(rt1019); + links[i].ops = &acp_card_rt1019_ops; + links[i].init = acp_card_rt1019_init; + card->codec_conf = rt1019_conf; + card->num_configs = ARRAY_SIZE(rt1019_conf); + } + i++; + } + if (drv_data->dmic_cpu_id == DMIC) { links[i].name = "acp-dmic-codec"; links[i].id = DMIC_BE_ID; @@ -634,8 +894,13 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) } links[i].cpus = pdm_dmic; links[i].num_cpus = ARRAY_SIZE(pdm_dmic); - links[i].platforms = platform_component; - links[i].num_platforms = ARRAY_SIZE(platform_component); + if (drv_data->platform == REMBRANDT) { + links[i].platforms = platform_rmb_component; + links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); + } else { + links[i].platforms = platform_component; + links[i].num_platforms = ARRAY_SIZE(platform_component); + } links[i].ops = &acp_card_dmic_ops; links[i].dpcm_capture = 1; } diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h index 5dc47cfbff10..20583ef902df 100644 --- a/sound/soc/amd/acp/acp-mach.h +++ b/sound/soc/amd/acp/acp-mach.h @@ -26,6 +26,7 @@ enum be_id { enum cpu_endpoints { NONE = 0, + I2S_HS, I2S_SP, I2S_BT, DMIC, @@ -37,6 +38,12 @@ enum codec_endpoints { RT1019, MAX98360A, RT5682S, + NAU8825, +}; + +enum platform_end_point { + RENOIR = 0, + REMBRANDT, }; struct acp_card_drvdata { @@ -47,8 +54,10 @@ struct acp_card_drvdata { unsigned int amp_codec_id; unsigned int dmic_codec_id; unsigned int dai_fmt; + unsigned int platform; struct clk *wclk; struct clk *bclk; + bool soc_mclk; }; int acp_sofdsp_dai_links_create(struct snd_soc_card *card); diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index c893963ee2d0..2c8e960cc9a6 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -29,7 +29,7 @@ static struct platform_device *dmic_dev; static struct platform_device *pdev; -static const struct resource acp3x_res[] = { +static const struct resource acp_res[] = { { .start = 0, .end = ACP3x_REG_END - ACP3x_REG_START, @@ -70,36 +70,49 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id ret = pci_request_regions(pci, "AMD ACP3x audio"); if (ret < 0) { dev_err(&pci->dev, "pci_request_regions failed\n"); - return -ENOMEM; + ret = -ENOMEM; + goto disable_pci; } pci_set_master(pci); + res_acp = acp_res; + num_res = ARRAY_SIZE(acp_res); + switch (pci->revision) { case 0x01: - res_acp = acp3x_res; - num_res = ARRAY_SIZE(acp3x_res); chip->name = "acp_asoc_renoir"; chip->acp_rev = ACP3X_DEV; break; + case 0x6f: + chip->name = "acp_asoc_rembrandt"; + chip->acp_rev = ACP6X_DEV; + break; default: dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision); - return -EINVAL; + ret = -EINVAL; + goto release_regions; } dmic_dev = platform_device_register_data(dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(dmic_dev)) { dev_err(dev, "failed to create DMIC device\n"); - return PTR_ERR(dmic_dev); + ret = PTR_ERR(dmic_dev); + goto release_regions; } addr = pci_resource_start(pci, 0); chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0)); + if (!chip->base) { + ret = -ENOMEM; + goto release_regions; + } res = devm_kzalloc(&pci->dev, sizeof(struct resource) * num_res, GFP_KERNEL); if (!res) { platform_device_unregister(dmic_dev); - return -ENOMEM; + ret = -ENOMEM; + goto release_regions; } for (i = 0; i < num_res; i++, res_acp++) { @@ -128,9 +141,17 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id dev_err(&pci->dev, "cannot register %s device\n", pdevinfo.name); platform_device_unregister(dmic_dev); ret = PTR_ERR(pdev); + goto release_regions; } return ret; + +release_regions: + pci_release_regions(pci); +disable_pci: + pci_disable_device(pci); + + return ret; }; static void acp_pci_remove(struct pci_dev *pci) diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c index 424c6e0bb9d6..66ec6b6a5972 100644 --- a/sound/soc/amd/acp/acp-pdm.c +++ b/sound/soc/amd/acp/acp-pdm.c @@ -160,9 +160,9 @@ static int acp_dmic_dai_startup(struct snd_pcm_substream *substream, stream->reg_offset = ACP_REGION2_OFFSET; /* Enable DMIC Interrupts */ - ext_int_ctrl = readl(adata->acp_base + ACP_EXTERNAL_INTR_CNTL); + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0)); ext_int_ctrl |= PDM_DMA_INTR_MASK; - writel(ext_int_ctrl, adata->acp_base + ACP_EXTERNAL_INTR_CNTL); + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0)); return 0; } @@ -174,10 +174,10 @@ static void acp_dmic_dai_shutdown(struct snd_pcm_substream *substream, struct acp_dev_data *adata = dev_get_drvdata(dev); u32 ext_int_ctrl; - /* Disable DMIC interrrupts */ - ext_int_ctrl = readl(adata->acp_base + ACP_EXTERNAL_INTR_CNTL); + /* Disable DMIC interrupts */ + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0)); ext_int_ctrl |= ~PDM_DMA_INTR_MASK; - writel(ext_int_ctrl, adata->acp_base + ACP_EXTERNAL_INTR_CNTL); + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0)); } const struct snd_soc_dai_ops acp_dmic_dai_ops = { diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index 65a809e2c29f..f561d39b33e2 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -91,25 +91,38 @@ EXPORT_SYMBOL_NS_GPL(acp_machine_select, SND_SOC_ACP_COMMON); static irqreturn_t i2s_irq_handler(int irq, void *data) { struct acp_dev_data *adata = data; + struct acp_resource *rsrc = adata->rsrc; struct acp_stream *stream; u16 i2s_flag = 0; - u32 val, i; + u32 ext_intr_stat, ext_intr_stat1, i; if (!adata) return IRQ_NONE; - val = readl(adata->acp_base + ACP_EXTERNAL_INTR_STAT); + if (adata->rsrc->no_of_ctrls == 2) + ext_intr_stat1 = readl(ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1))); + + ext_intr_stat = readl(ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); for (i = 0; i < ACP_MAX_STREAM; i++) { stream = adata->stream[i]; - if (stream && (val & stream->irq_bit)) { - writel(stream->irq_bit, adata->acp_base + ACP_EXTERNAL_INTR_STAT); + if (stream && (ext_intr_stat & stream->irq_bit)) { + writel(stream->irq_bit, + ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); snd_pcm_period_elapsed(stream->substream); i2s_flag = 1; break; } + if (adata->rsrc->no_of_ctrls == 2) { + if (stream && (ext_intr_stat1 & stream->irq_bit)) { + writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(adata, + (rsrc->irqp_used - 1))); + snd_pcm_period_elapsed(stream->substream); + i2s_flag = 1; + break; + } + } } - if (i2s_flag) return IRQ_HANDLED; @@ -118,6 +131,7 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream) { + struct acp_resource *rsrc = adata->rsrc; u32 pte_reg, pte_size, reg_val; /* Use ATU base Group5 */ @@ -126,15 +140,17 @@ static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream stream->reg_offset = 0x02000000; /* Group Enable */ - reg_val = ACP_SRAM_PTE_OFFSET; + reg_val = rsrc->sram_pte_offset; writel(reg_val | BIT(31), adata->acp_base + pte_reg); writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + pte_size); + writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); } static void config_acp_dma(struct acp_dev_data *adata, int cpu_id, int size) { struct acp_stream *stream = adata->stream[cpu_id]; struct snd_pcm_substream *substream = stream->substream; + struct acp_resource *rsrc = adata->rsrc; dma_addr_t addr = substream->dma_buffer.addr; int num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT); u32 low, high, val; @@ -146,9 +162,9 @@ static void config_acp_dma(struct acp_dev_data *adata, int cpu_id, int size) /* Load the low address of page int ACP SRAM through SRBM */ low = lower_32_bits(addr); high = upper_32_bits(addr); - writel(low, adata->acp_base + ACP_SCRATCH_REG_0 + val); + writel(low, adata->acp_base + rsrc->scratch_reg_offset + val); high |= BIT(31); - writel(high, adata->acp_base + ACP_SCRATCH_REG_0 + val + 4); + writel(high, adata->acp_base + rsrc->scratch_reg_offset + val + 4); /* Move to next physically contiguous page */ val += 8; @@ -187,7 +203,7 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs } runtime->private_data = stream; - writel(1, adata->acp_base + ACP_EXTERNAL_INTR_ENB); + writel(1, ACP_EXTERNAL_INTR_ENB(adata)); return ret; } @@ -242,13 +258,6 @@ static int acp_dma_new(struct snd_soc_component *component, return 0; } -static int acp_dma_mmap(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - return snd_pcm_lib_default_mmap(substream, vma); -} - static int acp_dma_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { @@ -267,13 +276,13 @@ static int acp_dma_close(struct snd_soc_component *component, } static const struct snd_soc_component_driver acp_pcm_component = { - .name = DRV_NAME, - .open = acp_dma_open, - .close = acp_dma_close, - .hw_params = acp_dma_hw_params, - .pointer = acp_dma_pointer, - .mmap = acp_dma_mmap, - .pcm_construct = acp_dma_new, + .name = DRV_NAME, + .open = acp_dma_open, + .close = acp_dma_close, + .hw_params = acp_dma_hw_params, + .pointer = acp_dma_pointer, + .pcm_construct = acp_dma_new, + .legacy_dai_naming = 1, }; int acp_platform_register(struct device *dev) diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c new file mode 100644 index 000000000000..2b57c0ca4e99 --- /dev/null +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -0,0 +1,401 @@ +// 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 Renoir 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 "amd.h" + +#define DRV_NAME "acp_asoc_rembrandt" + +#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 + + +static int rmb_acp_init(void __iomem *base); +static int rmb_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_codecs amp_max = { + .num_codecs = 1, + .codecs = {"MX98360A"} +}; + +static struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines[] = { + { + .id = "10508825", + .drv_name = "rmb-nau8825-max", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_max, + }, + { + .id = "AMDI0007", + .drv_name = "rembrandt-acp", + }, + { + .id = "RTL5682", + .drv_name = "rmb-rt5682s-rt1019", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_rt1019, + }, + {}, +}; + +static struct snd_soc_dai_driver acp_rmb_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 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)); +} + +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 rmb_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 rmb_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 rembrandt_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 != ACP6X_DEV) { + dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); + return -ENODEV; + } + + rmb_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_rmb_dai; + adata->num_dai = ARRAY_SIZE(acp_rmb_dai); + adata->rsrc = &rsrc; + + adata->machines = snd_soc_acpi_amd_rmb_acp_machines; + acp_machine_select(adata); + + dev_set_drvdata(dev, adata); + acp6x_enable_interrupts(adata); + acp_platform_register(dev); + + return 0; +} + +static int rembrandt_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; + + chip = dev_get_platdata(&pdev->dev); + if (!chip || !chip->base) { + dev_err(&pdev->dev, "ACP chip data is NULL\n"); + return -ENODEV; + } + + rmb_acp_deinit(chip->base); + + acp6x_disable_interrupts(adata); + acp_platform_unregister(dev); + return 0; +} + +static struct platform_driver rembrandt_driver = { + .probe = rembrandt_audio_probe, + .remove = rembrandt_audio_remove, + .driver = { + .name = "acp_asoc_rembrandt", + }, +}; + +module_platform_driver(rembrandt_driver); + +MODULE_DESCRIPTION("AMD ACP Rembrandt 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/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c index 75c9229ece97..2a89a0d2e601 100644 --- a/sound/soc/amd/acp/acp-renoir.c +++ b/sound/soc/amd/acp/acp-renoir.c @@ -39,6 +39,17 @@ #define ACP_ERROR_MASK 0x20000000 #define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF +static struct acp_resource rsrc = { + .offset = 20, + .no_of_ctrls = 1, + .irqp_used = 0, + .irq_reg_offset = 0x1800, + .i2s_pin_cfg_offset = 0x1400, + .i2s_mode = 0x04, + .scratch_reg_offset = 0x12800, + .sram_pte_offset = 0x02052800, +}; + static struct snd_soc_acpi_codecs amp_rt1019 = { .num_codecs = 1, .codecs = {"10EC1019"} @@ -186,20 +197,24 @@ static int acp3x_reset(void __iomem *base) return readl_poll_timeout(base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT); } -static void acp3x_enable_interrupts(void __iomem *base) +static void acp3x_enable_interrupts(struct acp_dev_data *adata) { + struct acp_resource *rsrc = adata->rsrc; u32 ext_intr_ctrl; - writel(0x01, base + ACP_EXTERNAL_INTR_ENB); - ext_intr_ctrl = readl(base + ACP_EXTERNAL_INTR_CNTL); + 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, base + ACP_EXTERNAL_INTR_CNTL); + writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); } -static void acp3x_disable_interrupts(void __iomem *base) +static void acp3x_disable_interrupts(struct acp_dev_data *adata) { - writel(ACP_EXT_INTR_STAT_CLEAR_MASK, base + ACP_EXTERNAL_INTR_STAT); - writel(0x00, base + ACP_EXTERNAL_INTR_ENB); + 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 rn_acp_init(void __iomem *base) @@ -218,8 +233,6 @@ static int rn_acp_init(void __iomem *base) if (ret) return ret; - acp3x_enable_interrupts(base); - return 0; } @@ -227,8 +240,6 @@ static int rn_acp_deinit(void __iomem *base) { int ret = 0; - acp3x_disable_interrupts(base); - /* Reset */ ret = acp3x_reset(base); if (ret) @@ -290,11 +301,13 @@ static int renoir_audio_probe(struct platform_device *pdev) adata->dev = dev; adata->dai_driver = acp_renoir_dai; adata->num_dai = ARRAY_SIZE(acp_renoir_dai); + adata->rsrc = &rsrc; adata->machines = snd_soc_acpi_amd_acp_machines; acp_machine_select(adata); dev_set_drvdata(dev, adata); + acp3x_enable_interrupts(adata); acp_platform_register(dev); return 0; @@ -303,20 +316,17 @@ static int renoir_audio_probe(struct platform_device *pdev) static int renoir_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; int ret; chip = dev_get_platdata(&pdev->dev); - if (!chip || !chip->base) { - dev_err(&pdev->dev, "ACP chip data is NULL\n"); - return -ENODEV; - } + + acp3x_disable_interrupts(adata); ret = rn_acp_deinit(chip->base); - if (ret) { - dev_err(&pdev->dev, "ACP de-init Failed\n"); - return -EINVAL; - } + if (ret) + dev_err(&pdev->dev, "ACP de-init Failed (%pe)\n", ERR_PTR(ret)); acp_platform_unregister(dev); return 0; diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c index d1531cdab110..f19f064a7527 100644 --- a/sound/soc/amd/acp/acp-sof-mach.c +++ b/sound/soc/amd/acp/acp-sof-mach.c @@ -56,6 +56,26 @@ static struct acp_card_drvdata sof_rt5682s_max_data = { .dmic_codec_id = DMIC, }; +static struct acp_card_drvdata sof_nau8825_data = { + .hs_cpu_id = I2S_HS, + .amp_cpu_id = I2S_HS, + .dmic_cpu_id = DMIC, + .hs_codec_id = NAU8825, + .amp_codec_id = MAX98360A, + .dmic_codec_id = DMIC, + .soc_mclk = true, +}; + +static struct acp_card_drvdata sof_rt5682s_hs_rt1019_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, +}; + static const struct snd_kcontrol_new acp_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), @@ -124,6 +144,14 @@ static const struct platform_device_id board_ids[] = { .name = "rt5682s-rt1019", .driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data }, + { + .name = "nau8825-max", + .driver_data = (kernel_ulong_t)&sof_nau8825_data + }, + { + .name = "rt5682s-hs-rt1019", + .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data + }, { } }; static struct platform_driver acp_asoc_audio = { @@ -143,4 +171,6 @@ MODULE_ALIAS("platform:rt5682-rt1019"); MODULE_ALIAS("platform:rt5682-max"); MODULE_ALIAS("platform:rt5682s-max"); MODULE_ALIAS("platform:rt5682s-rt1019"); +MODULE_ALIAS("platform:nau8825-max"); +MODULE_ALIAS("platform:rt5682s-hs-rt1019"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 8fd38bf4d3bd..af9603724a68 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -19,10 +19,12 @@ #include "chip_offset_byte.h" #define ACP3X_DEV 3 +#define ACP6X_DEV 6 #define I2S_SP_INSTANCE 0x00 #define I2S_BT_INSTANCE 0x01 #define DMIC_INSTANCE 0x02 +#define I2S_HS_INSTANCE 0x03 #define MEM_WINDOW_START 0x4080000 @@ -32,30 +34,37 @@ #define ACP3x_I2STDM_REG_END 0x1242410 #define ACP3x_BT_TDM_REG_START 0x1242800 #define ACP3x_BT_TDM_REG_END 0x1242810 -#define I2S_MODE 0x04 -#define I2S_RX_THRESHOLD 27 -#define I2S_TX_THRESHOLD 28 -#define BT_TX_THRESHOLD 26 -#define BT_RX_THRESHOLD 25 -#define ACP_SRAM_PTE_OFFSET 0x02052800 +#define THRESHOLD(bit, base) ((bit) + (base)) +#define I2S_RX_THRESHOLD(base) THRESHOLD(7, base) +#define I2S_TX_THRESHOLD(base) THRESHOLD(8, base) +#define BT_TX_THRESHOLD(base) THRESHOLD(6, base) +#define BT_RX_THRESHOLD(base) THRESHOLD(5, base) +#define HS_TX_THRESHOLD(base) THRESHOLD(4, base) +#define HS_RX_THRESHOLD(base) THRESHOLD(3, base) #define ACP_SRAM_SP_PB_PTE_OFFSET 0x0 #define ACP_SRAM_SP_CP_PTE_OFFSET 0x100 #define ACP_SRAM_BT_PB_PTE_OFFSET 0x200 #define ACP_SRAM_BT_CP_PTE_OFFSET 0x300 #define ACP_SRAM_PDM_PTE_OFFSET 0x400 +#define ACP_SRAM_HS_PB_PTE_OFFSET 0x500 +#define ACP_SRAM_HS_CP_PTE_OFFSET 0x600 #define PAGE_SIZE_4K_ENABLE 0x2 #define I2S_SP_TX_MEM_WINDOW_START 0x4000000 #define I2S_SP_RX_MEM_WINDOW_START 0x4020000 #define I2S_BT_TX_MEM_WINDOW_START 0x4040000 #define I2S_BT_RX_MEM_WINDOW_START 0x4060000 +#define I2S_HS_TX_MEM_WINDOW_START 0x40A0000 +#define I2S_HS_RX_MEM_WINDOW_START 0x40C0000 #define SP_PB_FIFO_ADDR_OFFSET 0x500 #define SP_CAPT_FIFO_ADDR_OFFSET 0x700 #define BT_PB_FIFO_ADDR_OFFSET 0x900 #define BT_CAPT_FIFO_ADDR_OFFSET 0xB00 +#define HS_PB_FIFO_ADDR_OFFSET 0xD00 +#define HS_CAPT_FIFO_ADDR_OFFSET 0xF00 #define PLAYBACK_MIN_NUM_PERIODS 2 #define PLAYBACK_MAX_NUM_PERIODS 8 #define PLAYBACK_MAX_PERIOD_SIZE 8192 @@ -73,7 +82,7 @@ #define ACP3x_ITER_IRER_SAMP_LEN_MASK 0x38 -#define ACP_MAX_STREAM 6 +#define ACP_MAX_STREAM 8 struct acp_chip_info { char *name; /* Platform name */ @@ -92,6 +101,18 @@ struct acp_stream { u32 fifo_offset; }; +struct acp_resource { + int offset; + int no_of_ctrls; + int irqp_used; + bool soc_mclk; + u32 irq_reg_offset; + u32 i2s_pin_cfg_offset; + int i2s_mode; + u64 scratch_reg_offset; + u64 sram_pte_offset; +}; + struct acp_dev_data { char *name; struct device *dev; @@ -106,6 +127,22 @@ struct acp_dev_data { struct snd_soc_acpi_mach *machines; struct platform_device *mach_dev; + + u32 bclk_div; + u32 lrclk_div; + + struct acp_resource *rsrc; +}; + +union acp_i2stdm_mstrclkgen { + struct { + u32 i2stdm_master_mode : 1; + u32 i2stdm_format_mode : 1; + u32 i2stdm_lrclk_div_val : 9; + u32 i2stdm_bclk_div_val : 11; + u32:10; + } bitfields, bits; + u32 u32_all; }; extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops; @@ -134,6 +171,10 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int high = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH); low = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_LOW); break; + case I2S_HS_INSTANCE: + high = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_HIGH); + low = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_LOW); + break; default: dev_err(adata->dev, "Invalid dai id %x\n", dai_id); return -EINVAL; @@ -148,6 +189,10 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int high = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH); low = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_LOW); break; + case I2S_HS_INSTANCE: + high = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_HIGH); + low = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_LOW); + break; case DMIC_INSTANCE: high = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH); low = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW); @@ -163,4 +208,31 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int return byte_count; } +static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id) +{ + union acp_i2stdm_mstrclkgen mclkgen; + u32 master_reg; + + switch (dai_id) { + case I2S_SP_INSTANCE: + master_reg = ACP_I2STDM0_MSTRCLKGEN; + break; + case I2S_BT_INSTANCE: + master_reg = ACP_I2STDM1_MSTRCLKGEN; + break; + case I2S_HS_INSTANCE: + master_reg = ACP_I2STDM2_MSTRCLKGEN; + break; + default: + master_reg = ACP_I2STDM0_MSTRCLKGEN; + break; + } + + mclkgen.bits.i2stdm_master_mode = 0x1; + mclkgen.bits.i2stdm_format_mode = 0x00; + + mclkgen.bits.i2stdm_bclk_div_val = adata->bclk_div; + mclkgen.bits.i2stdm_lrclk_div_val = adata->lrclk_div; + writel(mclkgen.u32_all, adata->acp_base + master_reg); +} #endif diff --git a/sound/soc/amd/acp/chip_offset_byte.h b/sound/soc/amd/acp/chip_offset_byte.h index 88f6fa597cd6..ce3948e0679c 100644 --- a/sound/soc/amd/acp/chip_offset_byte.h +++ b/sound/soc/amd/acp/chip_offset_byte.h @@ -20,11 +20,13 @@ #define ACP_SOFT_RESET 0x1000 #define ACP_CONTROL 0x1004 -#define ACP_EXTERNAL_INTR_ENB 0x1800 -#define ACP_EXTERNAL_INTR_CNTL 0x1804 -#define ACP_EXTERNAL_INTR_STAT 0x1808 -#define ACP_I2S_PIN_CONFIG 0x1400 -#define ACP_SCRATCH_REG_0 0x12800 +#define ACP_EXTERNAL_INTR_REG_ADDR(adata, offset, ctrl) \ + (adata->acp_base + adata->rsrc->irq_reg_offset + offset + (ctrl * 0x04)) + +#define ACP_EXTERNAL_INTR_ENB(adata) ACP_EXTERNAL_INTR_REG_ADDR(adata, 0x0, 0x0) +#define ACP_EXTERNAL_INTR_CNTL(adata, ctrl) ACP_EXTERNAL_INTR_REG_ADDR(adata, 0x4, ctrl) +#define ACP_EXTERNAL_INTR_STAT(adata, ctrl) ACP_EXTERNAL_INTR_REG_ADDR(adata, \ + (0x4 + (adata->rsrc->no_of_ctrls * 0x04)), ctrl) /* Registers from ACP_AUDIO_BUFFERS block */ @@ -64,6 +66,24 @@ #define ACP_BT_TX_LINEARPOSITIONCNTR_HIGH 0x2084 #define ACP_BT_TX_LINEARPOSITIONCNTR_LOW 0x2088 #define ACP_BT_TX_INTR_WATERMARK_SIZE 0x208C +#define ACP_HS_RX_RINGBUFADDR 0x3A90 +#define ACP_HS_RX_RINGBUFSIZE 0x3A94 +#define ACP_HS_RX_LINKPOSITIONCNTR 0x3A98 +#define ACP_HS_RX_FIFOADDR 0x3A9C +#define ACP_HS_RX_FIFOSIZE 0x3AA0 +#define ACP_HS_RX_DMA_SIZE 0x3AA4 +#define ACP_HS_RX_LINEARPOSITIONCNTR_HIGH 0x3AA8 +#define ACP_HS_RX_LINEARPOSITIONCNTR_LOW 0x3AAC +#define ACP_HS_RX_INTR_WATERMARK_SIZE 0x3AB0 +#define ACP_HS_TX_RINGBUFADDR 0x3AB4 +#define ACP_HS_TX_RINGBUFSIZE 0x3AB8 +#define ACP_HS_TX_LINKPOSITIONCNTR 0x3ABC +#define ACP_HS_TX_FIFOADDR 0x3AC0 +#define ACP_HS_TX_FIFOSIZE 0x3AC4 +#define ACP_HS_TX_DMA_SIZE 0x3AC8 +#define ACP_HS_TX_LINEARPOSITIONCNTR_HIGH 0x3ACC +#define ACP_HS_TX_LINEARPOSITIONCNTR_LOW 0x3AD0 +#define ACP_HS_TX_INTR_WATERMARK_SIZE 0x3AD4 #define ACP_I2STDM_IER 0x2400 #define ACP_I2STDM_IRER 0x2404 @@ -79,6 +99,13 @@ #define ACP_BTTDM_ITER 0x280C #define ACP_BTTDM_TXFRMT 0x2810 +/* Registers from ACP_HS_TDM block */ +#define ACP_HSTDM_IER 0x2814 +#define ACP_HSTDM_IRER 0x2818 +#define ACP_HSTDM_RXFRMT 0x281C +#define ACP_HSTDM_ITER 0x2820 +#define ACP_HSTDM_TXFRMT 0x2824 + /* Registers from ACP_WOV_PDM block */ #define ACP_WOV_PDM_ENABLE 0x2C04 @@ -99,4 +126,7 @@ #define ACP_PDM_VAD_DYNAMIC_CLK_GATING_EN 0x2C64 #define ACP_WOV_ERROR_STATUS_REGISTER 0x2C68 +#define ACP_I2STDM0_MSTRCLKGEN 0x2414 +#define ACP_I2STDM1_MSTRCLKGEN 0x2418 +#define ACP_I2STDM2_MSTRCLKGEN 0x241C #endif diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index 0a54567a2841..7b4c625da40d 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -19,6 +19,7 @@ #define ACP_PCI_DEV_ID 0x15E2 extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[]; struct config_entry { u32 flags; diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c index de6f70d7ef36..aa38cef1776d 100644 --- a/sound/soc/amd/raven/acp3x-i2s.c +++ b/sound/soc/amd/raven/acp3x-i2s.c @@ -257,7 +257,8 @@ static const struct snd_soc_dai_ops acp3x_i2s_dai_ops = { }; static const struct snd_soc_component_driver acp3x_dai_component = { - .name = DRV_NAME, + .name = DRV_NAME, + .legacy_dai_naming = 1, }; static struct snd_soc_dai_driver acp3x_i2s_dai = { diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c index 8c42345ee41e..7203c6488df0 100644 --- a/sound/soc/amd/renoir/acp3x-pdm-dma.c +++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c @@ -363,12 +363,13 @@ static struct snd_soc_dai_driver acp_pdm_dai_driver = { }; static const struct snd_soc_component_driver acp_pdm_component = { - .name = DRV_NAME, - .open = acp_pdm_dma_open, - .close = acp_pdm_dma_close, - .hw_params = acp_pdm_dma_hw_params, - .pointer = acp_pdm_dma_pointer, - .pcm_construct = acp_pdm_dma_new, + .name = DRV_NAME, + .open = acp_pdm_dma_open, + .close = acp_pdm_dma_close, + .hw_params = acp_pdm_dma_hw_params, + .pointer = acp_pdm_dma_pointer, + .pcm_construct = acp_pdm_dma_new, + .legacy_dai_naming = 1, }; static int acp_pdm_audio_probe(struct platform_device *pdev) diff --git a/sound/soc/amd/rpl/Makefile b/sound/soc/amd/rpl/Makefile new file mode 100644 index 000000000000..11a33a05e94b --- /dev/null +++ b/sound/soc/amd/rpl/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# RPL platform Support +snd-rpl-pci-acp6x-objs := rpl-pci-acp6x.o + +obj-$(CONFIG_SND_SOC_AMD_RPL_ACP6x) += snd-rpl-pci-acp6x.o diff --git a/sound/soc/amd/rpl/rpl-pci-acp6x.c b/sound/soc/amd/rpl/rpl-pci-acp6x.c new file mode 100644 index 000000000000..a8e548ed991b --- /dev/null +++ b/sound/soc/amd/rpl/rpl-pci-acp6x.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * AMD RPL ACP PCI Driver + * + * Copyright 2022 Advanced Micro Devices, Inc. + */ + +#include <linux/pci.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#include "rpl_acp6x.h" + +struct rpl_dev_data { + void __iomem *acp6x_base; +}; + +static int rpl_power_on(void __iomem *acp_base) +{ + u32 val; + int timeout; + + val = rpl_acp_readl(acp_base + ACP_PGFSM_STATUS); + + if (!val) + return val; + + if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS) + rpl_acp_writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL); + timeout = 0; + while (++timeout < 500) { + val = rpl_acp_readl(acp_base + ACP_PGFSM_STATUS); + if (!val) + return 0; + udelay(1); + } + return -ETIMEDOUT; +} + +static int rpl_reset(void __iomem *acp_base) +{ + u32 val; + int timeout; + + rpl_acp_writel(1, acp_base + ACP_SOFT_RESET); + timeout = 0; + while (++timeout < 500) { + val = rpl_acp_readl(acp_base + ACP_SOFT_RESET); + if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK) + break; + cpu_relax(); + } + rpl_acp_writel(0, acp_base + ACP_SOFT_RESET); + timeout = 0; + while (++timeout < 500) { + val = rpl_acp_readl(acp_base + ACP_SOFT_RESET); + if (!val) + return 0; + cpu_relax(); + } + return -ETIMEDOUT; +} + +static int rpl_init(void __iomem *acp_base) +{ + int ret; + + /* power on */ + ret = rpl_power_on(acp_base); + if (ret) { + pr_err("ACP power on failed\n"); + return ret; + } + rpl_acp_writel(0x01, acp_base + ACP_CONTROL); + /* Reset */ + ret = rpl_reset(acp_base); + if (ret) { + pr_err("ACP reset failed\n"); + return ret; + } + rpl_acp_writel(0x03, acp_base + ACP_CLKMUX_SEL); + return 0; +} + +static int rpl_deinit(void __iomem *acp_base) +{ + int ret; + + /* Reset */ + ret = rpl_reset(acp_base); + if (ret) { + pr_err("ACP reset failed\n"); + return ret; + } + rpl_acp_writel(0x00, acp_base + ACP_CLKMUX_SEL); + rpl_acp_writel(0x00, acp_base + ACP_CONTROL); + return 0; +} + +static int snd_rpl_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + struct rpl_dev_data *adata; + u32 addr; + int ret; + + /* RPL device check */ + switch (pci->revision) { + case 0x62: + break; + default: + dev_dbg(&pci->dev, "acp6x pci device not found\n"); + return -ENODEV; + } + if (pci_enable_device(pci)) { + dev_err(&pci->dev, "pci_enable_device failed\n"); + return -ENODEV; + } + + ret = pci_request_regions(pci, "AMD ACP6x audio"); + if (ret < 0) { + dev_err(&pci->dev, "pci_request_regions failed\n"); + goto disable_pci; + } + + adata = devm_kzalloc(&pci->dev, sizeof(struct rpl_dev_data), + GFP_KERNEL); + if (!adata) { + ret = -ENOMEM; + goto release_regions; + } + + addr = pci_resource_start(pci, 0); + adata->acp6x_base = devm_ioremap(&pci->dev, addr, + pci_resource_len(pci, 0)); + if (!adata->acp6x_base) { + ret = -ENOMEM; + goto release_regions; + } + pci_set_master(pci); + pci_set_drvdata(pci, adata); + ret = rpl_init(adata->acp6x_base); + if (ret) + goto release_regions; + pm_runtime_set_autosuspend_delay(&pci->dev, ACP_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(&pci->dev); + pm_runtime_put_noidle(&pci->dev); + pm_runtime_allow(&pci->dev); + + return 0; +release_regions: + pci_release_regions(pci); +disable_pci: + pci_disable_device(pci); + + return ret; +} + +static int __maybe_unused snd_rpl_suspend(struct device *dev) +{ + struct rpl_dev_data *adata; + int ret; + + adata = dev_get_drvdata(dev); + ret = rpl_deinit(adata->acp6x_base); + if (ret) + dev_err(dev, "ACP de-init failed\n"); + return ret; +} + +static int __maybe_unused snd_rpl_resume(struct device *dev) +{ + struct rpl_dev_data *adata; + int ret; + + adata = dev_get_drvdata(dev); + ret = rpl_init(adata->acp6x_base); + if (ret) + dev_err(dev, "ACP init failed\n"); + return ret; +} + +static const struct dev_pm_ops rpl_pm = { + SET_RUNTIME_PM_OPS(snd_rpl_suspend, snd_rpl_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(snd_rpl_suspend, snd_rpl_resume) +}; + +static void snd_rpl_remove(struct pci_dev *pci) +{ + struct rpl_dev_data *adata; + int ret; + + adata = pci_get_drvdata(pci); + ret = rpl_deinit(adata->acp6x_base); + if (ret) + dev_err(&pci->dev, "ACP de-init failed\n"); + pm_runtime_forbid(&pci->dev); + pm_runtime_get_noresume(&pci->dev); + pci_release_regions(pci); + pci_disable_device(pci); +} + +static const struct pci_device_id snd_rpl_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID), + .class = PCI_CLASS_MULTIMEDIA_OTHER << 8, + .class_mask = 0xffffff }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, snd_rpl_ids); + +static struct pci_driver rpl_acp6x_driver = { + .name = KBUILD_MODNAME, + .id_table = snd_rpl_ids, + .probe = snd_rpl_probe, + .remove = snd_rpl_remove, + .driver = { + .pm = &rpl_pm, + } +}; + +module_pci_driver(rpl_acp6x_driver); + +MODULE_DESCRIPTION("AMD ACP RPL PCI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/rpl/rpl_acp6x.h b/sound/soc/amd/rpl/rpl_acp6x.h new file mode 100644 index 000000000000..f5816a33632e --- /dev/null +++ b/sound/soc/amd/rpl/rpl_acp6x.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * AMD ACP Driver + * + * Copyright (C) 2021 Advanced Micro Devices, Inc. All rights reserved. + */ + +#include "rpl_acp6x_chip_offset_byte.h" + +#define ACP_DEVICE_ID 0x15E2 +#define ACP6x_PHY_BASE_ADDRESS 0x1240000 + +#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001 +#define ACP_PGFSM_CNTL_POWER_ON_MASK 1 +#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0 +#define ACP_PGFSM_STATUS_MASK 3 +#define ACP_POWERED_ON 0 +#define ACP_POWER_ON_IN_PROGRESS 1 +#define ACP_POWERED_OFF 2 +#define ACP_POWER_OFF_IN_PROGRESS 3 + +#define DELAY_US 5 +#define ACP_COUNTER 20000 + +/* time in ms for runtime suspend delay */ +#define ACP_SUSPEND_DELAY_MS 2000 + +static inline u32 rpl_acp_readl(void __iomem *base_addr) +{ + return readl(base_addr - ACP6x_PHY_BASE_ADDRESS); +} + +static inline void rpl_acp_writel(u32 val, void __iomem *base_addr) +{ + writel(val, base_addr - ACP6x_PHY_BASE_ADDRESS); +} diff --git a/sound/soc/amd/rpl/rpl_acp6x_chip_offset_byte.h b/sound/soc/amd/rpl/rpl_acp6x_chip_offset_byte.h new file mode 100644 index 000000000000..456498f5396d --- /dev/null +++ b/sound/soc/amd/rpl/rpl_acp6x_chip_offset_byte.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * AMD ACP 6.2 Register Documentation + * + * Copyright 2022 Advanced Micro Devices, Inc. + */ + +#ifndef _rpl_acp6x_OFFSET_HEADER +#define _rpl_acp6x_OFFSET_HEADER + +/* Registers from ACP_CLKRST block */ +#define ACP_SOFT_RESET 0x1241000 +#define ACP_CONTROL 0x1241004 +#define ACP_STATUS 0x1241008 +#define ACP_DYNAMIC_CG_MASTER_CONTROL 0x1241010 +#define ACP_PGFSM_CONTROL 0x124101C +#define ACP_PGFSM_STATUS 0x1241020 +#define ACP_CLKMUX_SEL 0x1241024 + +/* Registers from ACP_AON block */ +#define ACP_PME_EN 0x1241400 +#define ACP_DEVICE_STATE 0x1241404 +#define AZ_DEVICE_STATE 0x1241408 +#define ACP_PIN_CONFIG 0x1241440 +#define ACP_PAD_PULLUP_CTRL 0x1241444 +#define ACP_PAD_PULLDOWN_CTRL 0x1241448 +#define ACP_PAD_DRIVE_STRENGTH_CTRL 0x124144C +#define ACP_PAD_SCHMEN_CTRL 0x1241450 + +#endif diff --git a/sound/soc/amd/vangogh/acp5x-i2s.c b/sound/soc/amd/vangogh/acp5x-i2s.c index 59a98f89a669..773e96f1b4dd 100644 --- a/sound/soc/amd/vangogh/acp5x-i2s.c +++ b/sound/soc/amd/vangogh/acp5x-i2s.c @@ -37,10 +37,10 @@ static int acp5x_i2s_set_fmt(struct snd_soc_dai *cpu_dai, } mode = fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; switch (mode) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: adata->master_mode = I2S_MASTER_MODE_ENABLE; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: adata->master_mode = I2S_MASTER_MODE_DISABLE; break; } @@ -345,6 +345,7 @@ static const struct snd_soc_dai_ops acp5x_i2s_dai_ops = { static const struct snd_soc_component_driver acp5x_dai_component = { .name = "acp5x-i2s", + .legacy_dai_naming = 1, }; static struct snd_soc_dai_driver acp5x_i2s_dai = { diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c index 727de46860b1..af3737ef9707 100644 --- a/sound/soc/amd/vangogh/acp5x-mach.c +++ b/sound/soc/amd/vangogh/acp5x-mach.c @@ -178,8 +178,7 @@ static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream, ret = 0; for (i = 0; i < num_codecs; i++) { codec_dai = asoc_rtd_to_codec(rtd, i); - if ((strcmp(codec_dai->name, "spi-VLV1776:00") == 0) || - (strcmp(codec_dai->name, "spi-VLV1776:01") == 0)) { + if (strcmp(codec_dai->name, "cs35l41-pcm") == 0) { switch (params_rate(params)) { case 48000: bclk_val = 1536000; diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index f06e6c1a7799..ecfe7a790790 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -105,28 +105,14 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21AW"), + DMI_MATCH(DMI_PRODUCT_NAME, "21CM"), } }, { .driver_data = &acp6x_card, .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21AX"), - } - }, - { - .driver_data = &acp6x_card, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21BN"), - } - }, - { - .driver_data = &acp6x_card, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21BQ"), + DMI_MATCH(DMI_PRODUCT_NAME, "21CN"), } }, { @@ -157,20 +143,6 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "21CL"), } }, - { - .driver_data = &acp6x_card, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21D8"), - } - }, - { - .driver_data = &acp6x_card, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "21D9"), - } - }, {} }; diff --git a/sound/soc/amd/yc/acp6x-pdm-dma.c b/sound/soc/amd/yc/acp6x-pdm-dma.c index 7e66393e4153..acecd6a4ec4b 100644 --- a/sound/soc/amd/yc/acp6x-pdm-dma.c +++ b/sound/soc/amd/yc/acp6x-pdm-dma.c @@ -335,12 +335,13 @@ static struct snd_soc_dai_driver acp6x_pdm_dai_driver = { }; static const struct snd_soc_component_driver acp6x_pdm_component = { - .name = DRV_NAME, - .open = acp6x_pdm_dma_open, - .close = acp6x_pdm_dma_close, - .hw_params = acp6x_pdm_dma_hw_params, - .pointer = acp6x_pdm_dma_pointer, - .pcm_construct = acp6x_pdm_dma_new, + .name = DRV_NAME, + .open = acp6x_pdm_dma_open, + .close = acp6x_pdm_dma_close, + .hw_params = acp6x_pdm_dma_hw_params, + .pointer = acp6x_pdm_dma_pointer, + .pcm_construct = acp6x_pdm_dma_new, + .legacy_dai_naming = 1, }; static int acp6x_pdm_audio_probe(struct platform_device *pdev) diff --git a/sound/soc/amd/yc/pci-acp6x.c b/sound/soc/amd/yc/pci-acp6x.c index 20f7a99783f2..77c5fa1f7af1 100644 --- a/sound/soc/amd/yc/pci-acp6x.c +++ b/sound/soc/amd/yc/pci-acp6x.c @@ -159,7 +159,7 @@ static int snd_acp6x_probe(struct pci_dev *pci, case 0x6f: break; default: - dev_err(&pci->dev, "acp6x pci device not found\n"); + dev_dbg(&pci->dev, "acp6x pci device not found\n"); return -ENODEV; } if (pci_enable_device(pci)) { |