forked from Minki/linux
ADD SOF support for rembrandt platform
Merge series from V sujith kumar Reddy <Vsujithkumar.Reddy@amd.com>: This series consists of 1.Make ACP core code generic for newer SOC transition 2.Add support for Rembrandt plaform 3.Adding amd HS functionality to the sof core 4.increase SRAM inbox and outbox size to 1024
This commit is contained in:
commit
1dc53232a9
@ -84,6 +84,7 @@ enum sof_ipc_dai_type {
|
||||
SOF_DAI_AMD_BT, /**< AMD ACP BT*/
|
||||
SOF_DAI_AMD_SP, /**< AMD ACP SP */
|
||||
SOF_DAI_AMD_DMIC, /**< AMD ACP DMIC */
|
||||
SOF_DAI_AMD_HS, /**< Amd HS */
|
||||
SOF_DAI_MEDIATEK_AFE, /**< Mediatek AFE */
|
||||
};
|
||||
|
||||
@ -112,6 +113,7 @@ struct sof_ipc_dai_config {
|
||||
struct sof_ipc_dai_acp_params acpbt;
|
||||
struct sof_ipc_dai_acp_params acpsp;
|
||||
struct sof_ipc_dai_acpdmic_params acpdmic;
|
||||
struct sof_ipc_dai_acp_params acphs;
|
||||
struct sof_ipc_dai_mtk_afe_params afe;
|
||||
};
|
||||
} __packed;
|
||||
|
@ -31,4 +31,14 @@ config SND_SOC_SOF_AMD_RENOIR
|
||||
select SND_SOC_SOF_AMD_COMMON
|
||||
help
|
||||
Select this option for SOF support on AMD Renoir platform
|
||||
|
||||
config SND_SOC_SOF_AMD_REMBRANDT
|
||||
tristate "SOF support for REMBRANDT"
|
||||
depends on SND_SOC_SOF_PCI
|
||||
select SND_SOC_SOF_AMD_COMMON
|
||||
help
|
||||
Select this option for SOF support on AMD Rembrandt platform
|
||||
Say Y if you want to enable SOF on Rembrandt.
|
||||
If unsure select "N".
|
||||
|
||||
endif
|
||||
|
@ -4,8 +4,10 @@
|
||||
#
|
||||
# Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o
|
||||
snd-sof-amd-acp-objs := acp.o acp-loader.o acp-ipc.o acp-pcm.o acp-stream.o acp-trace.o acp-common.o
|
||||
snd-sof-amd-renoir-objs := pci-rn.o renoir.o
|
||||
snd-sof-amd-rembrandt-objs := pci-rmb.o rembrandt.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o
|
||||
obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) +=snd-sof-amd-renoir.o
|
||||
obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) +=snd-sof-amd-rembrandt.o
|
||||
|
111
sound/soc/sof/amd/acp-common.c
Normal file
111
sound/soc/sof/amd/acp-common.c
Normal file
@ -0,0 +1,111 @@
|
||||
// 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>
|
||||
|
||||
/* ACP-specific Common code */
|
||||
|
||||
#include "../sof-priv.h"
|
||||
#include "../sof-audio.h"
|
||||
#include "../ops.h"
|
||||
#include "../sof-audio.h"
|
||||
#include "acp.h"
|
||||
#include "acp-dsp-offset.h"
|
||||
|
||||
int acp_dai_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
unsigned int val;
|
||||
|
||||
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->i2s_pin_config_offset);
|
||||
if (val != desc->i2s_mode) {
|
||||
dev_err(sdev->dev, "I2S Mode is not supported (I2S_PIN_CONFIG: %#x)\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS(acp_dai_probe, SND_SOC_SOF_AMD_COMMON);
|
||||
|
||||
struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct snd_sof_pdata *sof_pdata = sdev->pdata;
|
||||
const struct sof_dev_desc *desc = sof_pdata->desc;
|
||||
struct snd_soc_acpi_mach *mach;
|
||||
|
||||
mach = snd_soc_acpi_find_machine(desc->machines);
|
||||
if (!mach) {
|
||||
dev_warn(sdev->dev, "No matching ASoC machine driver found\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sof_pdata->tplg_filename = mach->sof_tplg_filename;
|
||||
sof_pdata->fw_filename = mach->fw_filename;
|
||||
|
||||
return mach;
|
||||
}
|
||||
|
||||
/* AMD Common DSP ops */
|
||||
struct snd_sof_dsp_ops sof_acp_common_ops = {
|
||||
/* probe and remove */
|
||||
.probe = amd_sof_acp_probe,
|
||||
.remove = amd_sof_acp_remove,
|
||||
|
||||
/* Register IO */
|
||||
.write = sof_io_write,
|
||||
.read = sof_io_read,
|
||||
|
||||
/* Block IO */
|
||||
.block_read = acp_dsp_block_read,
|
||||
.block_write = acp_dsp_block_write,
|
||||
|
||||
/*Firmware loading */
|
||||
.load_firmware = snd_sof_load_firmware_memcpy,
|
||||
.pre_fw_run = acp_dsp_pre_fw_run,
|
||||
.get_bar_index = acp_get_bar_index,
|
||||
|
||||
/* DSP core boot */
|
||||
.run = acp_sof_dsp_run,
|
||||
|
||||
/*IPC */
|
||||
.send_msg = acp_sof_ipc_send_msg,
|
||||
.ipc_msg_data = acp_sof_ipc_msg_data,
|
||||
.get_mailbox_offset = acp_sof_ipc_get_mailbox_offset,
|
||||
.get_window_offset = acp_sof_ipc_get_window_offset,
|
||||
.irq_thread = acp_sof_ipc_irq_thread,
|
||||
|
||||
/* stream callbacks */
|
||||
.pcm_open = acp_pcm_open,
|
||||
.pcm_close = acp_pcm_close,
|
||||
.pcm_hw_params = acp_pcm_hw_params,
|
||||
|
||||
.hw_info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
|
||||
|
||||
/* Machine driver callbacks */
|
||||
.machine_select = amd_sof_machine_select,
|
||||
.machine_register = sof_machine_register,
|
||||
.machine_unregister = sof_machine_unregister,
|
||||
|
||||
/* Trace Logger */
|
||||
.trace_init = acp_sof_trace_init,
|
||||
.trace_release = acp_sof_trace_release,
|
||||
|
||||
/* PM */
|
||||
.suspend = amd_sof_acp_suspend,
|
||||
.resume = amd_sof_acp_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_NS(sof_acp_common_ops, SND_SOC_SOF_AMD_COMMON);
|
||||
|
||||
MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
|
||||
MODULE_DESCRIPTION("ACP SOF COMMON Driver");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
@ -48,22 +48,29 @@
|
||||
#define ACP_SOFT_RESET 0x1000
|
||||
#define ACP_CONTROL 0x1004
|
||||
|
||||
#define ACP_I2S_PIN_CONFIG 0x1400
|
||||
#define ACP3X_I2S_PIN_CONFIG 0x1400
|
||||
#define ACP6X_I2S_PIN_CONFIG 0x1440
|
||||
|
||||
/* Registers from ACP_PGFSM block */
|
||||
#define ACP_PGFSM_CONTROL 0x141C
|
||||
#define ACP_PGFSM_STATUS 0x1420
|
||||
#define ACP_CLKMUX_SEL 0x1424
|
||||
/* Registers offsets from ACP_PGFSM block */
|
||||
#define ACP3X_PGFSM_BASE 0x141C
|
||||
#define ACP6X_PGFSM_BASE 0x1024
|
||||
#define PGFSM_CONTROL_OFFSET 0x0
|
||||
#define PGFSM_STATUS_OFFSET 0x4
|
||||
#define ACP3X_CLKMUX_SEL 0x1424
|
||||
#define ACP6X_CLKMUX_SEL 0x102C
|
||||
|
||||
/* Registers from ACP_INTR block */
|
||||
#define ACP_EXTERNAL_INTR_ENB 0x1800
|
||||
#define ACP_EXTERNAL_INTR_CNTL 0x1804
|
||||
#define ACP_EXTERNAL_INTR_STAT 0x1808
|
||||
#define ACP_DSP_SW_INTR_CNTL 0x1814
|
||||
#define ACP_DSP_SW_INTR_STAT 0x1818
|
||||
#define ACP_SW_INTR_TRIG 0x181C
|
||||
#define ACP3X_EXT_INTR_STAT 0x1808
|
||||
#define ACP6X_EXT_INTR_STAT 0x1A0C
|
||||
|
||||
#define ACP3X_DSP_SW_INTR_BASE 0x1814
|
||||
#define ACP6X_DSP_SW_INTR_BASE 0x1808
|
||||
#define DSP_SW_INTR_CNTL_OFFSET 0x0
|
||||
#define DSP_SW_INTR_STAT_OFFSET 0x4
|
||||
#define DSP_SW_INTR_TRIG_OFFSET 0x8
|
||||
#define ACP_ERROR_STATUS 0x18C4
|
||||
#define ACP_AXI2DAGB_SEM_0 0x1880
|
||||
#define ACP3X_AXI2DAGB_SEM_0 0x1880
|
||||
#define ACP6X_AXI2DAGB_SEM_0 0x1874
|
||||
|
||||
/* Registers from ACP_SHA block */
|
||||
#define ACP_SHA_DSP_FW_QUALIFIER 0x1C70
|
||||
@ -77,5 +84,5 @@
|
||||
#define ACP_SHA_PSP_ACK 0x1C74
|
||||
|
||||
#define ACP_SCRATCH_REG_0 0x10000
|
||||
|
||||
#define ACP6X_DSP_FUSION_RUNSTALL 0x0644
|
||||
#endif
|
||||
|
@ -30,30 +30,36 @@ EXPORT_SYMBOL_NS(acp_mailbox_read, SND_SOC_SOF_AMD_COMMON);
|
||||
static void acpbus_trigger_host_to_dsp_swintr(struct acp_dev_data *adata)
|
||||
{
|
||||
struct snd_sof_dev *sdev = adata->dev;
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
u32 swintr_trigger;
|
||||
|
||||
swintr_trigger = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SW_INTR_TRIG);
|
||||
swintr_trigger = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->dsp_intr_base +
|
||||
DSP_SW_INTR_TRIG_OFFSET);
|
||||
swintr_trigger |= 0x01;
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW_INTR_TRIG, swintr_trigger);
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->dsp_intr_base + DSP_SW_INTR_TRIG_OFFSET,
|
||||
swintr_trigger);
|
||||
}
|
||||
|
||||
static void acp_ipc_host_msg_set(struct snd_sof_dev *sdev)
|
||||
{
|
||||
unsigned int host_msg = offsetof(struct scratch_ipc_conf, sof_host_msg_write);
|
||||
unsigned int host_msg = sdev->debug_box.offset +
|
||||
offsetof(struct scratch_ipc_conf, sof_host_msg_write);
|
||||
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + host_msg, 1);
|
||||
}
|
||||
|
||||
static void acp_dsp_ipc_host_done(struct snd_sof_dev *sdev)
|
||||
{
|
||||
unsigned int dsp_msg = offsetof(struct scratch_ipc_conf, sof_dsp_msg_write);
|
||||
unsigned int dsp_msg = sdev->debug_box.offset +
|
||||
offsetof(struct scratch_ipc_conf, sof_dsp_msg_write);
|
||||
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg, 0);
|
||||
}
|
||||
|
||||
static void acp_dsp_ipc_dsp_done(struct snd_sof_dev *sdev)
|
||||
{
|
||||
unsigned int dsp_ack = offsetof(struct scratch_ipc_conf, sof_dsp_ack_write);
|
||||
unsigned int dsp_ack = sdev->debug_box.offset +
|
||||
offsetof(struct scratch_ipc_conf, sof_dsp_ack_write);
|
||||
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack, 0);
|
||||
}
|
||||
@ -61,10 +67,11 @@ static void acp_dsp_ipc_dsp_done(struct snd_sof_dev *sdev)
|
||||
int acp_sof_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
|
||||
{
|
||||
struct acp_dev_data *adata = sdev->pdata->hw_pdata;
|
||||
unsigned int offset = offsetof(struct scratch_ipc_conf, sof_in_box);
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
unsigned int offset = sdev->host_box.offset;
|
||||
unsigned int count = ACP_HW_SEM_RETRY_COUNT;
|
||||
|
||||
while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_AXI2DAGB_SEM_0)) {
|
||||
while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) {
|
||||
/* Wait until acquired HW Semaphore Lock or timeout*/
|
||||
count--;
|
||||
if (!count) {
|
||||
@ -80,7 +87,7 @@ int acp_sof_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
|
||||
acpbus_trigger_host_to_dsp_swintr(adata);
|
||||
|
||||
/* Unlock or Release HW Semaphore */
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_AXI2DAGB_SEM_0, 0x0);
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset, 0x0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -91,7 +98,7 @@ static void acp_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
|
||||
struct snd_sof_ipc_msg *msg = sdev->msg;
|
||||
struct sof_ipc_reply reply;
|
||||
struct sof_ipc_cmd_hdr *hdr;
|
||||
unsigned int offset = offsetof(struct scratch_ipc_conf, sof_in_box);
|
||||
unsigned int offset = sdev->host_box.offset;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
@ -141,11 +148,19 @@ out:
|
||||
irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
|
||||
{
|
||||
struct snd_sof_dev *sdev = context;
|
||||
unsigned int dsp_msg_write = offsetof(struct scratch_ipc_conf, sof_dsp_msg_write);
|
||||
unsigned int dsp_ack_write = offsetof(struct scratch_ipc_conf, sof_dsp_ack_write);
|
||||
unsigned int dsp_msg_write = sdev->debug_box.offset +
|
||||
offsetof(struct scratch_ipc_conf, sof_dsp_msg_write);
|
||||
unsigned int dsp_ack_write = sdev->debug_box.offset +
|
||||
offsetof(struct scratch_ipc_conf, sof_dsp_ack_write);
|
||||
bool ipc_irq = false;
|
||||
int dsp_msg, dsp_ack;
|
||||
|
||||
if (sdev->first_boot && sdev->fw_state != SOF_FW_BOOT_COMPLETE) {
|
||||
snd_sof_ipc_msgs_rx(sdev);
|
||||
acp_dsp_ipc_host_done(sdev);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
dsp_msg = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_msg_write);
|
||||
if (dsp_msg) {
|
||||
snd_sof_ipc_msgs_rx(sdev);
|
||||
@ -175,7 +190,7 @@ EXPORT_SYMBOL_NS(acp_sof_ipc_irq_thread, SND_SOC_SOF_AMD_COMMON);
|
||||
int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
|
||||
void *p, size_t sz)
|
||||
{
|
||||
unsigned int offset = offsetof(struct scratch_ipc_conf, sof_out_box);
|
||||
unsigned int offset = sdev->dsp_box.offset;
|
||||
|
||||
if (!substream || !sdev->stream_box.size)
|
||||
acp_mailbox_read(sdev, offset, p, sz);
|
||||
@ -186,8 +201,16 @@ EXPORT_SYMBOL_NS(acp_sof_ipc_msg_data, SND_SOC_SOF_AMD_COMMON);
|
||||
|
||||
int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
|
||||
{
|
||||
return ACP_SCRATCH_MEMORY_ADDRESS;
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
|
||||
return desc->sram_pte_offset;
|
||||
}
|
||||
EXPORT_SYMBOL_NS(acp_sof_ipc_get_mailbox_offset, SND_SOC_SOF_AMD_COMMON);
|
||||
|
||||
int acp_sof_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS(acp_sof_ipc_get_window_offset, SND_SOC_SOF_AMD_COMMON);
|
||||
|
||||
MODULE_DESCRIPTION("AMD ACP sof-ipc driver");
|
||||
|
@ -30,9 +30,10 @@
|
||||
int acp_dsp_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type,
|
||||
u32 offset, void *dest, size_t size)
|
||||
{
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
switch (blk_type) {
|
||||
case SOF_FW_BLK_TYPE_SRAM:
|
||||
offset = offset - ACP_SCRATCH_MEMORY_ADDRESS;
|
||||
offset = offset - desc->sram_pte_offset;
|
||||
memcpy_from_scratch(sdev, offset, dest, size);
|
||||
break;
|
||||
default:
|
||||
@ -49,6 +50,7 @@ int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_t
|
||||
{
|
||||
struct snd_sof_pdata *plat_data = sdev->pdata;
|
||||
struct pci_dev *pci = to_pci_dev(sdev->dev);
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
struct acp_dev_data *adata;
|
||||
void *dest;
|
||||
u32 dma_size, page_count;
|
||||
@ -84,7 +86,7 @@ int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_t
|
||||
adata->fw_data_bin_size = size + offset;
|
||||
break;
|
||||
case SOF_FW_BLK_TYPE_SRAM:
|
||||
offset = offset - ACP_SCRATCH_MEMORY_ADDRESS;
|
||||
offset = offset - desc->sram_pte_offset;
|
||||
memcpy_to_scratch(sdev, offset, src, size);
|
||||
return 0;
|
||||
default:
|
||||
@ -105,14 +107,13 @@ EXPORT_SYMBOL_NS(acp_get_bar_index, SND_SOC_SOF_AMD_COMMON);
|
||||
|
||||
static void configure_pte_for_fw_loading(int type, int num_pages, struct acp_dev_data *adata)
|
||||
{
|
||||
struct snd_sof_dev *sdev;
|
||||
struct snd_sof_dev *sdev = adata->dev;
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
unsigned int low, high;
|
||||
dma_addr_t addr;
|
||||
u16 page_idx;
|
||||
u32 offset;
|
||||
|
||||
sdev = adata->dev;
|
||||
|
||||
switch (type) {
|
||||
case FW_BIN:
|
||||
offset = FW_BIN_PTE_OFFSET;
|
||||
@ -129,7 +130,7 @@ static void configure_pte_for_fw_loading(int type, int num_pages, struct acp_dev
|
||||
|
||||
/* Group Enable */
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_BASE_ADDR_GRP_1,
|
||||
ACP_SRAM_PTE_OFFSET | BIT(31));
|
||||
desc->sram_pte_offset | BIT(31));
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1,
|
||||
PAGE_SIZE_4K_ENABLE);
|
||||
|
||||
@ -197,12 +198,19 @@ EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, SND_SOC_SOF_AMD_COMMON);
|
||||
|
||||
int acp_sof_dsp_run(struct snd_sof_dev *sdev)
|
||||
{
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
int val;
|
||||
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP0_RUNSTALL, ACP_DSP_RUN);
|
||||
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP0_RUNSTALL);
|
||||
dev_dbg(sdev->dev, "ACP_DSP0_RUNSTALL : 0x%0x\n", val);
|
||||
|
||||
/* Some platforms won't support fusion DSP,keep offset zero for no support */
|
||||
if (desc->fusion_dsp_offset) {
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset, ACP_DSP_RUN);
|
||||
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->fusion_dsp_offset);
|
||||
dev_dbg(sdev->dev, "ACP_DSP0_FUSION_RUNSTALL : 0x%0x\n", val);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS(acp_sof_dsp_run, SND_SOC_SOF_AMD_COMMON);
|
||||
|
@ -42,7 +42,8 @@ int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substr
|
||||
|
||||
/* write buffer size of stream in scratch memory */
|
||||
|
||||
buf_offset = offsetof(struct scratch_reg_conf, buf_size);
|
||||
buf_offset = sdev->debug_box.offset +
|
||||
offsetof(struct scratch_reg_conf, buf_size);
|
||||
index = stream->stream_tag - 1;
|
||||
buf_offset = buf_offset + index * 4;
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
int acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *stream)
|
||||
{
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
unsigned int pte_reg, pte_size, phy_addr_offset, index;
|
||||
int stream_tag = stream->stream_tag;
|
||||
u32 low, high, offset, reg_val;
|
||||
@ -88,7 +89,8 @@ int acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *strea
|
||||
|
||||
/* write phy_addr in scratch memory */
|
||||
|
||||
phy_addr_offset = offsetof(struct scratch_reg_conf, reg_offset);
|
||||
phy_addr_offset = sdev->debug_box.offset +
|
||||
offsetof(struct scratch_reg_conf, reg_offset);
|
||||
index = stream_tag - 1;
|
||||
phy_addr_offset = phy_addr_offset + index * 4;
|
||||
|
||||
@ -96,7 +98,8 @@ int acp_dsp_stream_config(struct snd_sof_dev *sdev, struct acp_dsp_stream *strea
|
||||
phy_addr_offset, stream->reg_offset);
|
||||
|
||||
/* Group Enable */
|
||||
reg_val = ACP_SRAM_PTE_OFFSET + offset;
|
||||
offset = offset + sdev->debug_box.offset;
|
||||
reg_val = desc->sram_pte_offset + offset;
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, pte_reg, reg_val | BIT(31));
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, pte_size, PAGE_SIZE_4K_ENABLE);
|
||||
|
||||
|
@ -39,9 +39,11 @@ static int smn_read(struct pci_dev *dev, u32 smn_addr, u32 *data)
|
||||
static void init_dma_descriptor(struct acp_dev_data *adata)
|
||||
{
|
||||
struct snd_sof_dev *sdev = adata->dev;
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
unsigned int addr;
|
||||
|
||||
addr = ACP_SRAM_PTE_OFFSET + offsetof(struct scratch_reg_conf, dma_desc);
|
||||
addr = desc->sram_pte_offset + sdev->debug_box.offset +
|
||||
offsetof(struct scratch_reg_conf, dma_desc);
|
||||
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DESC_BASE_ADDR, addr);
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DMA_DESC_MAX_NUM_DSCR, ACP_MAX_DESC_CNT);
|
||||
@ -53,7 +55,8 @@ static void configure_dma_descriptor(struct acp_dev_data *adata, unsigned short
|
||||
struct snd_sof_dev *sdev = adata->dev;
|
||||
unsigned int offset;
|
||||
|
||||
offset = ACP_SCRATCH_REG_0 + offsetof(struct scratch_reg_conf, dma_desc) +
|
||||
offset = ACP_SCRATCH_REG_0 + sdev->debug_box.offset +
|
||||
offsetof(struct scratch_reg_conf, dma_desc) +
|
||||
idx * sizeof(struct dma_descriptor);
|
||||
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, offset, dscr_info->src_addr);
|
||||
@ -300,8 +303,9 @@ void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src,
|
||||
static int acp_memory_init(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct acp_dev_data *adata = sdev->pdata->hw_pdata;
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
|
||||
snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_CNTL,
|
||||
snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR, desc->dsp_intr_base + DSP_SW_INTR_CNTL_OFFSET,
|
||||
ACP_DSP_INTR_EN_MASK, ACP_DSP_INTR_EN_MASK);
|
||||
init_dma_descriptor(adata);
|
||||
|
||||
@ -311,18 +315,20 @@ static int acp_memory_init(struct snd_sof_dev *sdev)
|
||||
static irqreturn_t acp_irq_thread(int irq, void *context)
|
||||
{
|
||||
struct snd_sof_dev *sdev = context;
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
unsigned int base = desc->dsp_intr_base;
|
||||
unsigned int val, count = ACP_HW_SEM_RETRY_COUNT;
|
||||
|
||||
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_EXTERNAL_INTR_STAT);
|
||||
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat);
|
||||
if (val & ACP_SHA_STAT) {
|
||||
/* Clear SHA interrupt raised by PSP */
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_EXTERNAL_INTR_STAT, val);
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, val);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT);
|
||||
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);
|
||||
if (val & ACP_DSP_TO_HOST_IRQ) {
|
||||
while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_AXI2DAGB_SEM_0)) {
|
||||
while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) {
|
||||
/* Wait until acquired HW Semaphore lock or timeout */
|
||||
count--;
|
||||
if (!count) {
|
||||
@ -333,10 +339,10 @@ static irqreturn_t acp_irq_thread(int irq, void *context)
|
||||
|
||||
sof_ops(sdev)->irq_thread(irq, sdev);
|
||||
val |= ACP_DSP_TO_HOST_IRQ;
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT, val);
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, val);
|
||||
|
||||
/* Unlock or Release HW Semaphore */
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_AXI2DAGB_SEM_0, 0x0);
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset, 0x0);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -347,9 +353,11 @@ static irqreturn_t acp_irq_thread(int irq, void *context)
|
||||
static irqreturn_t acp_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct snd_sof_dev *sdev = dev_id;
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
unsigned int base = desc->dsp_intr_base;
|
||||
unsigned int val;
|
||||
|
||||
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_DSP_SW_INTR_STAT);
|
||||
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);
|
||||
if (val)
|
||||
return IRQ_WAKE_THREAD;
|
||||
|
||||
@ -358,20 +366,22 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)
|
||||
|
||||
static int acp_power_on(struct snd_sof_dev *sdev)
|
||||
{
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
unsigned int base = desc->pgfsm_base;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_PGFSM_STATUS);
|
||||
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET);
|
||||
|
||||
if (val == ACP_POWERED_ON)
|
||||
return 0;
|
||||
|
||||
if (val & ACP_PGFSM_STATUS_MASK)
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_PGFSM_CONTROL,
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + PGFSM_CONTROL_OFFSET,
|
||||
ACP_PGFSM_CNTL_POWER_ON_MASK);
|
||||
|
||||
ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_PGFSM_STATUS, val, !val,
|
||||
ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US);
|
||||
ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET, val,
|
||||
!val, ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US);
|
||||
if (ret < 0)
|
||||
dev_err(sdev->dev, "timeout in ACP_PGFSM_STATUS read\n");
|
||||
|
||||
@ -437,6 +447,7 @@ EXPORT_SYMBOL_NS(amd_sof_acp_suspend, SND_SOC_SOF_AMD_COMMON);
|
||||
|
||||
int amd_sof_acp_resume(struct snd_sof_dev *sdev)
|
||||
{
|
||||
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
|
||||
int ret;
|
||||
|
||||
ret = acp_init(sdev);
|
||||
@ -445,7 +456,7 @@ int amd_sof_acp_resume(struct snd_sof_dev *sdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CLKMUX_SEL, 0x03);
|
||||
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, 0x03);
|
||||
|
||||
ret = acp_memory_init(sdev);
|
||||
|
||||
@ -507,6 +518,15 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
sdev->dsp_box.offset = 0;
|
||||
sdev->dsp_box.size = BOX_SIZE_512;
|
||||
|
||||
sdev->host_box.offset = sdev->dsp_box.offset + sdev->dsp_box.size;
|
||||
sdev->host_box.size = BOX_SIZE_512;
|
||||
|
||||
sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size;
|
||||
sdev->debug_box.size = BOX_SIZE_1024;
|
||||
|
||||
acp_memory_init(sdev);
|
||||
|
||||
acp_dsp_stream_init(sdev);
|
||||
|
@ -30,7 +30,8 @@
|
||||
#define ACP_SOFT_RESET_DONE_MASK 0x00010001
|
||||
|
||||
#define ACP_DSP_INTR_EN_MASK 0x00000001
|
||||
#define ACP_SRAM_PTE_OFFSET 0x02050000
|
||||
#define ACP3X_SRAM_PTE_OFFSET 0x02050000
|
||||
#define ACP6X_SRAM_PTE_OFFSET 0x03800000
|
||||
#define PAGE_SIZE_4K_ENABLE 0x2
|
||||
#define ACP_PAGE_SIZE 0x1000
|
||||
#define ACP_DMA_CH_RUN 0x02
|
||||
@ -45,7 +46,7 @@
|
||||
#define ACPBUS_REG_BASE_OFFSET ACP_DMA_CNTL_0
|
||||
|
||||
#define ACP_DEFAULT_DRAM_LENGTH 0x00080000
|
||||
#define ACP_SCRATCH_MEMORY_ADDRESS 0x02050000
|
||||
#define ACP3X_SCRATCH_MEMORY_ADDRESS 0x02050000
|
||||
#define ACP_SYSTEM_MEMORY_WINDOW 0x4000000
|
||||
#define ACP_IRAM_BASE_ADDRESS 0x000000
|
||||
#define ACP_DATA_RAM_BASE_ADDRESS 0x01000000
|
||||
@ -54,6 +55,7 @@
|
||||
#define ACP_DSP_TO_HOST_IRQ 0x04
|
||||
|
||||
#define HOST_BRIDGE_CZN 0x1630
|
||||
#define HOST_BRIDGE_RMB 0x14B5
|
||||
#define ACP_SHA_STAT 0x8000
|
||||
#define ACP_PSP_TIMEOUT_COUNTER 5
|
||||
#define ACP_EXT_INTR_ERROR_STAT 0x20000000
|
||||
@ -64,6 +66,9 @@
|
||||
#define MBOX_READY_MASK 0x80000000
|
||||
#define MBOX_STATUS_MASK 0xFFFF
|
||||
|
||||
#define BOX_SIZE_512 0x200
|
||||
#define BOX_SIZE_1024 0x400
|
||||
|
||||
struct acp_atu_grp_pte {
|
||||
u32 low;
|
||||
u32 high;
|
||||
@ -88,10 +93,6 @@ struct dma_descriptor {
|
||||
|
||||
/* Scratch memory structure for communication b/w host and dsp */
|
||||
struct scratch_ipc_conf {
|
||||
/* DSP mailbox */
|
||||
u8 sof_out_box[512];
|
||||
/* Host mailbox */
|
||||
u8 sof_in_box[512];
|
||||
/* Debug memory */
|
||||
u8 sof_debug_box[1024];
|
||||
/* Exception memory*/
|
||||
@ -139,6 +140,20 @@ struct acp_dsp_stream {
|
||||
unsigned int reg_offset;
|
||||
};
|
||||
|
||||
struct sof_amd_acp_desc {
|
||||
unsigned int rev;
|
||||
unsigned int host_bridge_id;
|
||||
unsigned int i2s_mode;
|
||||
u32 pgfsm_base;
|
||||
u32 ext_intr_stat;
|
||||
u32 dsp_intr_base;
|
||||
u32 sram_pte_offset;
|
||||
u32 i2s_pin_config_offset;
|
||||
u32 hw_semaphore_offset;
|
||||
u32 acp_clkmux_sel;
|
||||
u32 fusion_dsp_offset;
|
||||
};
|
||||
|
||||
/* Common device data struct for ACP devices */
|
||||
struct acp_dev_data {
|
||||
struct snd_sof_dev *dev;
|
||||
@ -206,8 +221,15 @@ int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substr
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_sof_platform_stream_params *platform_params);
|
||||
|
||||
extern struct snd_sof_dsp_ops sof_renoir_ops;
|
||||
extern struct snd_sof_dsp_ops sof_acp_common_ops;
|
||||
|
||||
extern struct snd_sof_dsp_ops sof_renoir_ops;
|
||||
int sof_renoir_ops_init(struct snd_sof_dev *sdev);
|
||||
extern struct snd_sof_dsp_ops sof_rembrandt_ops;
|
||||
int sof_rembrandt_ops_init(struct snd_sof_dev *sdev);
|
||||
|
||||
int acp_dai_probe(struct snd_soc_dai *dai);
|
||||
struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev);
|
||||
/* Machine configuration */
|
||||
int snd_amd_acp_find_config(struct pci_dev *pci);
|
||||
|
||||
@ -220,10 +242,6 @@ int acp_sof_trace_release(struct snd_sof_dev *sdev);
|
||||
int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state);
|
||||
int amd_sof_acp_resume(struct snd_sof_dev *sdev);
|
||||
|
||||
struct sof_amd_acp_desc {
|
||||
unsigned int host_bridge_id;
|
||||
};
|
||||
|
||||
static inline const struct sof_amd_acp_desc *get_chip_info(struct snd_sof_pdata *pdata)
|
||||
{
|
||||
const struct sof_dev_desc *desc = pdata->desc;
|
||||
|
186
sound/soc/sof/amd/pci-rmb.c
Normal file
186
sound/soc/sof/amd/pci-rmb.c
Normal file
@ -0,0 +1,186 @@
|
||||
// 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. All rights reserved.
|
||||
//
|
||||
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
|
||||
|
||||
/*.
|
||||
* PCI interface for Rembrandt ACP device
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <sound/sof.h>
|
||||
#include <sound/soc-acpi.h>
|
||||
|
||||
#include "../ops.h"
|
||||
#include "../sof-pci-dev.h"
|
||||
#include "../../amd/mach-config.h"
|
||||
#include "acp.h"
|
||||
#include "acp-dsp-offset.h"
|
||||
|
||||
#define ACP6x_REG_START 0x1240000
|
||||
#define ACP6x_REG_END 0x125C000
|
||||
|
||||
static struct platform_device *dmic_dev;
|
||||
static struct platform_device *pdev;
|
||||
|
||||
static const struct resource rembrandt_res[] = {
|
||||
{
|
||||
.start = 0,
|
||||
.end = ACP6x_REG_END - ACP6x_REG_START,
|
||||
.name = "acp_mem",
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = 0,
|
||||
.end = 0,
|
||||
.name = "acp_dai_irq",
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct sof_amd_acp_desc rembrandt_chip_info = {
|
||||
.rev = 6,
|
||||
.host_bridge_id = HOST_BRIDGE_RMB,
|
||||
.i2s_mode = 0x0a,
|
||||
.pgfsm_base = ACP6X_PGFSM_BASE,
|
||||
.ext_intr_stat = ACP6X_EXT_INTR_STAT,
|
||||
.dsp_intr_base = ACP6X_DSP_SW_INTR_BASE,
|
||||
.sram_pte_offset = ACP6X_SRAM_PTE_OFFSET,
|
||||
.i2s_pin_config_offset = ACP6X_I2S_PIN_CONFIG,
|
||||
.hw_semaphore_offset = ACP6X_AXI2DAGB_SEM_0,
|
||||
.acp_clkmux_sel = ACP6X_CLKMUX_SEL,
|
||||
.fusion_dsp_offset = ACP6X_DSP_FUSION_RUNSTALL,
|
||||
};
|
||||
|
||||
static const struct sof_dev_desc rembrandt_desc = {
|
||||
.machines = snd_soc_acpi_amd_rmb_sof_machines,
|
||||
.resindex_lpe_base = 0,
|
||||
.resindex_pcicfg_base = -1,
|
||||
.resindex_imr_base = -1,
|
||||
.irqindex_host_ipc = -1,
|
||||
.chip_info = &rembrandt_chip_info,
|
||||
.ipc_supported_mask = BIT(SOF_IPC),
|
||||
.ipc_default = SOF_IPC,
|
||||
.default_fw_path = {
|
||||
[SOF_IPC] = "amd/sof",
|
||||
},
|
||||
.default_tplg_path = {
|
||||
[SOF_IPC] = "amd/sof-tplg",
|
||||
},
|
||||
.default_fw_filename = {
|
||||
[SOF_IPC] = "sof-rmb.ri",
|
||||
},
|
||||
.nocodec_tplg_filename = "sof-acp.tplg",
|
||||
.ops = &sof_rembrandt_ops,
|
||||
.ops_init = sof_rembrandt_ops_init,
|
||||
};
|
||||
|
||||
static int acp_pci_rmb_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
|
||||
{
|
||||
struct platform_device_info pdevinfo;
|
||||
struct device *dev = &pci->dev;
|
||||
const struct resource *res_i2s;
|
||||
struct resource *res;
|
||||
unsigned int flag, i, addr;
|
||||
int ret;
|
||||
|
||||
flag = snd_amd_acp_find_config(pci);
|
||||
if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC)
|
||||
return -ENODEV;
|
||||
|
||||
ret = sof_pci_probe(pci, pci_id);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
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");
|
||||
sof_pci_remove(pci);
|
||||
return PTR_ERR(dmic_dev);
|
||||
}
|
||||
|
||||
/* Register platform device only if flag set to FLAG_AMD_SOF_ONLY_DMIC */
|
||||
if (flag != FLAG_AMD_SOF_ONLY_DMIC)
|
||||
return 0;
|
||||
|
||||
addr = pci_resource_start(pci, 0);
|
||||
res = devm_kzalloc(&pci->dev, sizeof(struct resource) * ARRAY_SIZE(rembrandt_res),
|
||||
GFP_KERNEL);
|
||||
if (!res) {
|
||||
platform_device_unregister(dmic_dev);
|
||||
sof_pci_remove(pci);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
res_i2s = rembrandt_res;
|
||||
for (i = 0; i < ARRAY_SIZE(rembrandt_res); i++, res_i2s++) {
|
||||
res[i].name = res_i2s->name;
|
||||
res[i].flags = res_i2s->flags;
|
||||
res[i].start = addr + res_i2s->start;
|
||||
res[i].end = addr + res_i2s->end;
|
||||
if (res_i2s->flags == IORESOURCE_IRQ) {
|
||||
res[i].start = pci->irq;
|
||||
res[i].end = res[i].start;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&pdevinfo, 0, sizeof(pdevinfo));
|
||||
|
||||
/*
|
||||
* We have common PCI driver probe for ACP device but we have to support I2S without SOF
|
||||
* for some distributions. Register platform device that will be used to support non dsp
|
||||
* ACP's audio ends points on some machines.
|
||||
*/
|
||||
pdevinfo.name = "acp_asoc_rembrandt";
|
||||
pdevinfo.id = 0;
|
||||
pdevinfo.parent = &pci->dev;
|
||||
pdevinfo.num_res = ARRAY_SIZE(rembrandt_res);
|
||||
pdevinfo.res = &res[0];
|
||||
|
||||
pdev = platform_device_register_full(&pdevinfo);
|
||||
if (IS_ERR(pdev)) {
|
||||
dev_err(&pci->dev, "cannot register %s device\n", pdevinfo.name);
|
||||
platform_device_unregister(dmic_dev);
|
||||
sof_pci_remove(pci);
|
||||
ret = PTR_ERR(pdev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
static void acp_pci_rmb_remove(struct pci_dev *pci)
|
||||
{
|
||||
if (dmic_dev)
|
||||
platform_device_unregister(dmic_dev);
|
||||
if (pdev)
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
sof_pci_remove(pci);
|
||||
}
|
||||
|
||||
/* PCI IDs */
|
||||
static const struct pci_device_id rmb_pci_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID),
|
||||
.driver_data = (unsigned long)&rembrandt_desc},
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, rmb_pci_ids);
|
||||
|
||||
/* pci_driver definition */
|
||||
static struct pci_driver snd_sof_pci_amd_rmb_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = rmb_pci_ids,
|
||||
.probe = acp_pci_rmb_probe,
|
||||
.remove = acp_pci_rmb_remove,
|
||||
};
|
||||
module_pci_driver(snd_sof_pci_amd_rmb_driver);
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
|
||||
MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
|
@ -21,6 +21,7 @@
|
||||
#include "../sof-pci-dev.h"
|
||||
#include "../../amd/mach-config.h"
|
||||
#include "acp.h"
|
||||
#include "acp-dsp-offset.h"
|
||||
|
||||
#define ACP3x_REG_START 0x1240000
|
||||
#define ACP3x_REG_END 0x125C000
|
||||
@ -44,7 +45,16 @@ static const struct resource renoir_res[] = {
|
||||
};
|
||||
|
||||
static const struct sof_amd_acp_desc renoir_chip_info = {
|
||||
.rev = 3,
|
||||
.host_bridge_id = HOST_BRIDGE_CZN,
|
||||
.i2s_mode = 0x04,
|
||||
.pgfsm_base = ACP3X_PGFSM_BASE,
|
||||
.ext_intr_stat = ACP3X_EXT_INTR_STAT,
|
||||
.dsp_intr_base = ACP3X_DSP_SW_INTR_BASE,
|
||||
.sram_pte_offset = ACP3X_SRAM_PTE_OFFSET,
|
||||
.i2s_pin_config_offset = ACP3X_I2S_PIN_CONFIG,
|
||||
.hw_semaphore_offset = ACP3X_AXI2DAGB_SEM_0,
|
||||
.acp_clkmux_sel = ACP3X_CLKMUX_SEL,
|
||||
};
|
||||
|
||||
static const struct sof_dev_desc renoir_desc = {
|
||||
@ -68,6 +78,7 @@ static const struct sof_dev_desc renoir_desc = {
|
||||
},
|
||||
.nocodec_tplg_filename = "sof-acp.tplg",
|
||||
.ops = &sof_renoir_ops,
|
||||
.ops_init = sof_renoir_ops_init,
|
||||
};
|
||||
|
||||
static int acp_pci_rn_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
|
||||
|
134
sound/soc/sof/amd/rembrandt.c
Normal file
134
sound/soc/sof/amd/rembrandt.c
Normal file
@ -0,0 +1,134 @@
|
||||
// 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>
|
||||
|
||||
/*
|
||||
* Hardware interface for Audio DSP on Rembrandt platform
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "../ops.h"
|
||||
#include "../sof-audio.h"
|
||||
#include "acp.h"
|
||||
#include "acp-dsp-offset.h"
|
||||
|
||||
#define I2S_HS_INSTANCE 0
|
||||
#define I2S_BT_INSTANCE 1
|
||||
#define I2S_SP_INSTANCE 2
|
||||
#define PDM_DMIC_INSTANCE 3
|
||||
|
||||
static struct snd_soc_dai_driver rembrandt_sof_dai[] = {
|
||||
[I2S_HS_INSTANCE] = {
|
||||
.id = I2S_HS_INSTANCE,
|
||||
.name = "acp-sof-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 = {
|
||||
.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,
|
||||
/* Supporting only stereo for I2S HS controller capture */
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
.probe = &acp_dai_probe,
|
||||
},
|
||||
|
||||
[I2S_BT_INSTANCE] = {
|
||||
.id = I2S_BT_INSTANCE,
|
||||
.name = "acp-sof-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 = {
|
||||
.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,
|
||||
/* Supporting only stereo for I2S BT controller capture */
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
.probe = &acp_dai_probe,
|
||||
},
|
||||
|
||||
[I2S_SP_INSTANCE] = {
|
||||
.id = I2S_SP_INSTANCE,
|
||||
.name = "acp-sof-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 = {
|
||||
.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,
|
||||
/* Supporting only stereo for I2S SP controller capture */
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
.probe = &acp_dai_probe,
|
||||
},
|
||||
|
||||
[PDM_DMIC_INSTANCE] = {
|
||||
.id = PDM_DMIC_INSTANCE,
|
||||
.name = "acp-sof-dmic",
|
||||
.capture = {
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels_min = 2,
|
||||
.channels_max = 4,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/* Rembrandt ops */
|
||||
struct snd_sof_dsp_ops sof_rembrandt_ops;
|
||||
EXPORT_SYMBOL_NS(sof_rembrandt_ops, SND_SOC_SOF_AMD_COMMON);
|
||||
|
||||
int sof_rembrandt_ops_init(struct snd_sof_dev *sdev)
|
||||
{
|
||||
/* common defaults */
|
||||
memcpy(&sof_rembrandt_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops));
|
||||
|
||||
sof_rembrandt_ops.drv = rembrandt_sof_dai;
|
||||
sof_rembrandt_ops.num_drv = ARRAY_SIZE(rembrandt_sof_dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
|
||||
MODULE_DESCRIPTION("REMBRANDT SOF Driver");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
@ -23,22 +23,6 @@
|
||||
#define I2S_SP_INSTANCE 1
|
||||
#define PDM_DMIC_INSTANCE 2
|
||||
|
||||
#define I2S_MODE 0x04
|
||||
|
||||
static int renoir_dai_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
|
||||
unsigned int val;
|
||||
|
||||
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_I2S_PIN_CONFIG);
|
||||
if (val != I2S_MODE) {
|
||||
dev_err(sdev->dev, "I2S Mode is not supported (I2S_PIN_CONFIG: %#x)\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_driver renoir_sof_dai[] = {
|
||||
[I2S_BT_INSTANCE] = {
|
||||
.id = I2S_BT_INSTANCE,
|
||||
@ -62,7 +46,7 @@ static struct snd_soc_dai_driver renoir_sof_dai[] = {
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
.probe = &renoir_dai_probe,
|
||||
.probe = &acp_dai_probe,
|
||||
},
|
||||
|
||||
[I2S_SP_INSTANCE] = {
|
||||
@ -87,7 +71,7 @@ static struct snd_soc_dai_driver renoir_sof_dai[] = {
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
},
|
||||
.probe = &renoir_dai_probe,
|
||||
.probe = &acp_dai_probe,
|
||||
},
|
||||
|
||||
[PDM_DMIC_INSTANCE] = {
|
||||
@ -104,82 +88,21 @@ static struct snd_soc_dai_driver renoir_sof_dai[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev)
|
||||
/* Renoir ops */
|
||||
struct snd_sof_dsp_ops sof_renoir_ops;
|
||||
EXPORT_SYMBOL_NS(sof_renoir_ops, SND_SOC_SOF_AMD_COMMON);
|
||||
|
||||
int sof_renoir_ops_init(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct snd_sof_pdata *sof_pdata = sdev->pdata;
|
||||
const struct sof_dev_desc *desc = sof_pdata->desc;
|
||||
struct snd_soc_acpi_mach *mach;
|
||||
/* common defaults */
|
||||
memcpy(&sof_renoir_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops));
|
||||
|
||||
mach = snd_soc_acpi_find_machine(desc->machines);
|
||||
if (!mach) {
|
||||
dev_warn(sdev->dev, "No matching ASoC machine driver found\n");
|
||||
return NULL;
|
||||
sof_renoir_ops.drv = renoir_sof_dai;
|
||||
sof_renoir_ops.num_drv = ARRAY_SIZE(renoir_sof_dai);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sof_pdata->tplg_filename = mach->sof_tplg_filename;
|
||||
sof_pdata->fw_filename = mach->fw_filename;
|
||||
|
||||
return mach;
|
||||
}
|
||||
|
||||
/* AMD Renoir DSP ops */
|
||||
struct snd_sof_dsp_ops sof_renoir_ops = {
|
||||
/* probe and remove */
|
||||
.probe = amd_sof_acp_probe,
|
||||
.remove = amd_sof_acp_remove,
|
||||
|
||||
/* Register IO */
|
||||
.write = sof_io_write,
|
||||
.read = sof_io_read,
|
||||
|
||||
/* Block IO */
|
||||
.block_read = acp_dsp_block_read,
|
||||
.block_write = acp_dsp_block_write,
|
||||
|
||||
/*Firmware loading */
|
||||
.load_firmware = snd_sof_load_firmware_memcpy,
|
||||
.pre_fw_run = acp_dsp_pre_fw_run,
|
||||
.get_bar_index = acp_get_bar_index,
|
||||
|
||||
/* DSP core boot */
|
||||
.run = acp_sof_dsp_run,
|
||||
|
||||
/*IPC */
|
||||
.send_msg = acp_sof_ipc_send_msg,
|
||||
.ipc_msg_data = acp_sof_ipc_msg_data,
|
||||
.get_mailbox_offset = acp_sof_ipc_get_mailbox_offset,
|
||||
.irq_thread = acp_sof_ipc_irq_thread,
|
||||
|
||||
/* DAI drivers */
|
||||
.drv = renoir_sof_dai,
|
||||
.num_drv = ARRAY_SIZE(renoir_sof_dai),
|
||||
|
||||
/* stream callbacks */
|
||||
.pcm_open = acp_pcm_open,
|
||||
.pcm_close = acp_pcm_close,
|
||||
.pcm_hw_params = acp_pcm_hw_params,
|
||||
|
||||
.hw_info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
|
||||
|
||||
/* Machine driver callbacks */
|
||||
.machine_select = amd_sof_machine_select,
|
||||
.machine_register = sof_machine_register,
|
||||
.machine_unregister = sof_machine_unregister,
|
||||
|
||||
/* Trace Logger */
|
||||
.trace_init = acp_sof_trace_init,
|
||||
.trace_release = acp_sof_trace_release,
|
||||
|
||||
/* PM */
|
||||
.suspend = amd_sof_acp_suspend,
|
||||
.resume = amd_sof_acp_resume,
|
||||
};
|
||||
EXPORT_SYMBOL(sof_renoir_ops);
|
||||
|
||||
MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON);
|
||||
MODULE_DESCRIPTION("RENOIR SOF Driver");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
@ -346,6 +346,15 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
dev_dbg(component->dev, "AMD_SP channels_min: %d channels_max: %d\n",
|
||||
channels->min, channels->max);
|
||||
break;
|
||||
case SOF_DAI_AMD_HS:
|
||||
rate->min = private->dai_config->acphs.fsync_rate;
|
||||
rate->max = private->dai_config->acphs.fsync_rate;
|
||||
channels->min = private->dai_config->acphs.tdm_slots;
|
||||
channels->max = private->dai_config->acphs.tdm_slots;
|
||||
|
||||
dev_dbg(component->dev,
|
||||
"AMD_HS channel_max: %d rate_max: %d\n", channels->max, rate->max);
|
||||
break;
|
||||
case SOF_DAI_AMD_DMIC:
|
||||
rate->min = private->dai_config->acpdmic.pdm_rate;
|
||||
rate->max = private->dai_config->acpdmic.pdm_rate;
|
||||
|
@ -1217,6 +1217,36 @@ static int sof_link_acp_sp_load(struct snd_soc_component *scomp, struct snd_sof_
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sof_link_acp_hs_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
|
||||
struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
|
||||
{
|
||||
struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
|
||||
struct sof_dai_private_data *private = dai->private;
|
||||
u32 size = sizeof(*config);
|
||||
|
||||
/* Configures the DAI hardware format and inverted clocks */
|
||||
sof_dai_set_format(hw_config, config);
|
||||
|
||||
/* init IPC */
|
||||
memset(&config->acphs, 0, sizeof(config->acphs));
|
||||
config->hdr.size = size;
|
||||
|
||||
config->acphs.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
|
||||
config->acphs.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
|
||||
|
||||
dev_info(scomp->dev, "ACP_HS config ACP%d channel %d rate %d\n",
|
||||
config->dai_index, config->acphs.tdm_slots,
|
||||
config->acphs.fsync_rate);
|
||||
|
||||
dai->number_configs = 1;
|
||||
dai->current_config = 0;
|
||||
private->dai_config = kmemdup(config, size, GFP_KERNEL);
|
||||
if (!private->dai_config)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
|
||||
struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
|
||||
{
|
||||
@ -1517,6 +1547,9 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
|
||||
case SOF_DAI_AMD_SP:
|
||||
ret = sof_link_acp_sp_load(scomp, slink, config, dai);
|
||||
break;
|
||||
case SOF_DAI_AMD_HS:
|
||||
ret = sof_link_acp_hs_load(scomp, slink, config, dai);
|
||||
break;
|
||||
case SOF_DAI_AMD_DMIC:
|
||||
ret = sof_link_acp_dmic_load(scomp, slink, config, dai);
|
||||
break;
|
||||
|
@ -287,6 +287,7 @@ static const struct sof_dai_types sof_dais[] = {
|
||||
{"ACP", SOF_DAI_AMD_BT},
|
||||
{"ACPSP", SOF_DAI_AMD_SP},
|
||||
{"ACPDMIC", SOF_DAI_AMD_DMIC},
|
||||
{"ACPHS", SOF_DAI_AMD_HS},
|
||||
{"AFE", SOF_DAI_MEDIATEK_AFE},
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user