Skip to content
Closed
7 changes: 4 additions & 3 deletions sound/soc/sof/amd/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,14 @@ config SND_SOC_SOF_AMD_ACP63
If unsure select "N".

config SND_SOC_SOF_AMD_ACP70
tristate "SOF support for ACP7.0 platform"
tristate "SOF support for ACP7.0/ACP7.1 platforms"
depends on SND_SOC_SOF_PCI
depends on AMD_NODE
select SND_SOC_SOF_AMD_COMMON
select SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE
help
Select this option for SOF support on
AMD ACP7.0 version based platforms.
Say Y if you want to enable SOF on ACP7.0 based platform.
AMD ACP7.0/ACP7.1 version based platforms.
Say Y if you want to enable SOF on ACP7.0/ACP7.1 based platforms.

endif
10 changes: 10 additions & 0 deletions sound/soc/sof/amd/acp-dsp-offset.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,14 @@

#define ACP_SW0_EN 0x3000
#define ACP_SW1_EN 0x3C00
#define ACP70_PME_EN 0x1400
#define ACP70_EXTERNAL_INTR_CNTL1 0x1A08
#define ACP70_SW0_WAKE_EN 0x1458
#define ACP70_SW1_WAKE_EN 0x1460
#define ACP70_SDW_HOST_WAKE_MASK 0x0C00000
#define ACP70_SDW0_HOST_WAKE_STAT BIT(24)
#define ACP70_SDW1_HOST_WAKE_STAT BIT(25)
#define ACP70_SDW0_PME_STAT BIT(26)
#define ACP70_SDW1_PME_STAT BIT(27)

#endif
133 changes: 118 additions & 15 deletions sound/soc/sof/amd/acp.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ static void init_dma_descriptor(struct acp_dev_data *adata)

switch (acp_data->pci_rev) {
case ACP70_PCI_ID:
case ACP71_PCI_ID:
acp_dma_desc_base_addr = ACP70_DMA_DESC_BASE_ADDR;
acp_dma_desc_max_num_dscr = ACP70_DMA_DESC_MAX_NUM_DSCR;
break;
Expand Down Expand Up @@ -97,6 +98,7 @@ static int config_dma_channel(struct acp_dev_data *adata, unsigned int ch,

switch (acp_data->pci_rev) {
case ACP70_PCI_ID:
case ACP71_PCI_ID:
acp_dma_cntl_0 = ACP70_DMA_CNTL_0;
acp_dma_ch_rst_sts = ACP70_DMA_CH_RST_STS;
acp_dma_dscr_err_sts_0 = ACP70_DMA_ERR_STS_0;
Expand Down Expand Up @@ -336,6 +338,7 @@ int acp_dma_status(struct acp_dev_data *adata, unsigned char ch)

switch (adata->pci_rev) {
case ACP70_PCI_ID:
case ACP71_PCI_ID:
acp_dma_ch_sts = ACP70_DMA_CH_STS;
break;
default:
Expand Down Expand Up @@ -383,6 +386,69 @@ static int acp_memory_init(struct snd_sof_dev *sdev)
return 0;
}

static void amd_sof_handle_acp70_sdw_wake_event(struct acp_dev_data *adata)
{
struct amd_sdw_manager *amd_manager;

if (adata->acp70_sdw0_wake_event) {
amd_manager = dev_get_drvdata(&adata->sdw->pdev[0]->dev);
if (amd_manager)
pm_request_resume(amd_manager->dev);
adata->acp70_sdw0_wake_event = 0;
}

if (adata->acp70_sdw1_wake_event) {
amd_manager = dev_get_drvdata(&adata->sdw->pdev[1]->dev);
if (amd_manager)
pm_request_resume(amd_manager->dev);
adata->acp70_sdw1_wake_event = 0;
}
}

static int amd_sof_check_and_handle_acp70_sdw_wake_irq(struct snd_sof_dev *sdev)
{
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
struct acp_dev_data *adata = sdev->pdata->hw_pdata;
u32 ext_intr_stat1;
int irq_flag = 0;
bool sdw_wake_irq = false;

ext_intr_stat1 = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat1);
if (ext_intr_stat1 & ACP70_SDW0_HOST_WAKE_STAT) {
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1,
ACP70_SDW0_HOST_WAKE_STAT);
adata->acp70_sdw0_wake_event = true;
sdw_wake_irq = true;
}

if (ext_intr_stat1 & ACP70_SDW1_HOST_WAKE_STAT) {
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1,
ACP70_SDW1_HOST_WAKE_STAT);
adata->acp70_sdw1_wake_event = true;
sdw_wake_irq = true;
}

if (ext_intr_stat1 & ACP70_SDW0_PME_STAT) {
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP70_SW0_WAKE_EN, 0);
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1, ACP70_SDW0_PME_STAT);
adata->acp70_sdw0_wake_event = true;
sdw_wake_irq = true;
}

if (ext_intr_stat1 & ACP70_SDW1_PME_STAT) {
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP70_SW1_WAKE_EN, 0);
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1, ACP70_SDW1_PME_STAT);
adata->acp70_sdw1_wake_event = true;
sdw_wake_irq = true;
}

if (sdw_wake_irq) {
amd_sof_handle_acp70_sdw_wake_event(adata);
irq_flag = 1;
}
return irq_flag;
}

static irqreturn_t acp_irq_thread(int irq, void *context)
{
struct snd_sof_dev *sdev = context;
Expand Down Expand Up @@ -415,7 +481,7 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)
struct acp_dev_data *adata = sdev->pdata->hw_pdata;
unsigned int base = desc->dsp_intr_base;
unsigned int val;
int irq_flag = 0;
int irq_flag = 0, wake_irq_flag = 0;

val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);
if (val & ACP_DSP_TO_HOST_IRQ) {
Expand Down Expand Up @@ -453,8 +519,14 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)
schedule_work(&amd_manager->amd_sdw_irq_thread);
irq_flag = 1;
}
switch (adata->pci_rev) {
case ACP70_PCI_ID:
case ACP71_PCI_ID:
wake_irq_flag = amd_sof_check_and_handle_acp70_sdw_wake_irq(sdev);
break;
}
}
if (irq_flag)
if (irq_flag || wake_irq_flag)
return IRQ_HANDLED;
else
return IRQ_NONE;
Expand Down Expand Up @@ -486,6 +558,7 @@ static int acp_power_on(struct snd_sof_dev *sdev)
acp_pgfsm_cntl_mask = ACP6X_PGFSM_CNTL_POWER_ON_MASK;
break;
case ACP70_PCI_ID:
case ACP71_PCI_ID:
acp_pgfsm_status_mask = ACP70_PGFSM_STATUS_MASK;
acp_pgfsm_cntl_mask = ACP70_PGFSM_CNTL_POWER_ON_MASK;
break;
Expand All @@ -507,7 +580,6 @@ static int acp_power_on(struct snd_sof_dev *sdev)

static int acp_reset(struct snd_sof_dev *sdev)
{
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
unsigned int val;
int ret;

Expand All @@ -528,14 +600,6 @@ static int acp_reset(struct snd_sof_dev *sdev)
if (ret < 0)
dev_err(sdev->dev, "timeout in releasing reset\n");

if (desc->acp_clkmux_sel)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK);

if (desc->ext_intr_enb)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_enb, 0x01);

if (desc->ext_intr_cntl)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_cntl, ACP_ERROR_IRQ_MASK);
return ret;
}

Expand Down Expand Up @@ -566,9 +630,13 @@ static int acp_dsp_reset(struct snd_sof_dev *sdev)

static int acp_init(struct snd_sof_dev *sdev)
{
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
struct acp_dev_data *acp_data;
unsigned int sdw0_wake_en, sdw1_wake_en;
int ret;

/* power on */
acp_data = sdev->pdata->hw_pdata;
ret = acp_power_on(sdev);
if (ret) {
dev_err(sdev->dev, "ACP power on failed\n");
Expand All @@ -577,7 +645,32 @@ static int acp_init(struct snd_sof_dev *sdev)

snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, 0x01);
/* Reset */
return acp_reset(sdev);
ret = acp_reset(sdev);
if (ret)
return ret;

if (desc->acp_clkmux_sel)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_clkmux_sel, ACP_CLOCK_ACLK);

if (desc->ext_intr_enb)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_enb, 0x01);

if (desc->ext_intr_cntl)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_cntl, ACP_ERROR_IRQ_MASK);

switch (acp_data->pci_rev) {
case ACP70_PCI_ID:
case ACP71_PCI_ID:
sdw0_wake_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP70_SW0_WAKE_EN);
sdw1_wake_en = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP70_SW1_WAKE_EN);
if (sdw0_wake_en || sdw1_wake_en)
snd_sof_dsp_update_bits(sdev, ACP_DSP_BAR, ACP70_EXTERNAL_INTR_CNTL1,
ACP70_SDW_HOST_WAKE_MASK, ACP70_SDW_HOST_WAKE_MASK);

snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP70_PME_EN, 1);
break;
}
return 0;
}

static bool check_acp_sdw_enable_status(struct snd_sof_dev *sdev)
Expand Down Expand Up @@ -616,8 +709,12 @@ int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state)
dev_err(sdev->dev, "ACP Reset failed\n");
return ret;
}
if (acp_data->pci_rev == ACP70_PCI_ID)
switch (acp_data->pci_rev) {
case ACP70_PCI_ID:
case ACP71_PCI_ID:
enable = true;
break;
}
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable);

return 0;
Expand All @@ -637,9 +734,15 @@ int amd_sof_acp_resume(struct snd_sof_dev *sdev)
return ret;
}
return acp_memory_init(sdev);
} else {
return acp_dsp_reset(sdev);
}
switch (acp_data->pci_rev) {
case ACP70_PCI_ID:
case ACP71_PCI_ID:
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP70_PME_EN, 1);
break;
}

return acp_dsp_reset(sdev);
}
EXPORT_SYMBOL_NS(amd_sof_acp_resume, "SND_SOC_SOF_AMD_COMMON");

Expand Down
7 changes: 7 additions & 0 deletions sound/soc/sof/amd/acp.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
#define ACP_RMB_PCI_ID 0x6F
#define ACP63_PCI_ID 0x63
#define ACP70_PCI_ID 0x70
#define ACP71_PCI_ID 0x71

#define HOST_BRIDGE_CZN 0x1630
#define HOST_BRIDGE_VGH 0x1645
Expand Down Expand Up @@ -109,9 +110,11 @@
#define ACP_SDW0_IRQ_MASK BIT(21)
#define ACP_SDW1_IRQ_MASK BIT(2)
#define SDW_ACPI_ADDR_ACP63 5
#define SDW_ACPI_ADDR_ACP70 SDW_ACPI_ADDR_ACP63
#define ACP_DEFAULT_SRAM_LENGTH 0x00080000
#define ACP_SRAM_PAGE_COUNT 128
#define ACP6X_SDW_MAX_MANAGER_COUNT 2
#define ACP70_SDW_MAX_MANAGER_COUNT ACP6X_SDW_MAX_MANAGER_COUNT

enum clock_source {
ACP_CLOCK_96M = 0,
Expand Down Expand Up @@ -260,6 +263,10 @@ struct acp_dev_data {
bool is_dram_in_use;
bool is_sram_in_use;
bool sdw_en_stat;
/* acp70_sdw0_wake_event flag set to true when wake irq asserted for SW0 instance */
bool acp70_sdw0_wake_event;
/* acp70_sdw1_wake_event flag set to true when wake irq asserted for SW1 instance */
bool acp70_sdw1_wake_event;
unsigned int pci_rev;
};

Expand Down
10 changes: 9 additions & 1 deletion sound/soc/sof/amd/pci-acp70.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ static const struct sof_amd_acp_desc acp70_chip_info = {
.ext_intr_cntl = ACP70_EXTERNAL_INTR_CNTL,
.ext_intr_stat = ACP70_EXT_INTR_STAT,
.ext_intr_stat1 = ACP70_EXT_INTR_STAT1,
.acp_error_stat = ACP70_ERROR_STATUS,
.dsp_intr_base = ACP70_DSP_SW_INTR_BASE,
.acp_sw0_i2s_err_reason = ACP7X_SW0_I2S_ERROR_REASON,
.sram_pte_offset = ACP70_SRAM_PTE_OFFSET,
.hw_semaphore_offset = ACP70_AXI2DAGB_SEM_0,
.fusion_dsp_offset = ACP70_DSP_FUSION_RUNSTALL,
.probe_reg_offset = ACP70_FUTURE_REG_ACLK_0,
.sdw_max_link_count = ACP70_SDW_MAX_MANAGER_COUNT,
.sdw_acpi_dev_addr = SDW_ACPI_ADDR_ACP70,
.reg_start_addr = ACP70_REG_START,
.reg_end_addr = ACP70_REG_END,
};
Expand Down Expand Up @@ -70,8 +73,13 @@ static int acp70_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_
{
unsigned int flag;

if (pci->revision != ACP70_PCI_ID)
switch (pci->revision) {
case ACP70_PCI_ID:
case ACP71_PCI_ID:
break;
default:
return -ENODEV;
}

flag = snd_amd_acp_find_config(pci);
if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC)
Expand Down
Loading