diff options
Diffstat (limited to 'sound/soc/sof/amd/acp.c')
-rw-r--r-- | sound/soc/sof/amd/acp.c | 189 |
1 files changed, 134 insertions, 55 deletions
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 9e13c96528be..7132916aa253 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -16,6 +16,8 @@ #include <linux/module.h> #include <linux/pci.h> +#include <asm/amd/node.h> + #include "../ops.h" #include "acp.h" #include "acp-dsp-offset.h" @@ -43,24 +45,6 @@ const struct dmi_system_id acp_sof_quirk_table[] = { }; EXPORT_SYMBOL_GPL(acp_sof_quirk_table); -static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) -{ - pci_write_config_dword(dev, 0x60, smn_addr); - pci_write_config_dword(dev, 0x64, data); - - return 0; -} - -static int smn_read(struct pci_dev *dev, u32 smn_addr) -{ - u32 data = 0; - - pci_write_config_dword(dev, 0x60, smn_addr); - pci_read_config_dword(dev, 0x64, &data); - - return data; -} - static void init_dma_descriptor(struct acp_dev_data *adata) { struct snd_sof_dev *sdev = adata->dev; @@ -74,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; @@ -113,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; @@ -209,11 +195,11 @@ int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr, static int psp_mbox_ready(struct acp_dev_data *adata, bool ack) { struct snd_sof_dev *sdev = adata->dev; - int ret; - u32 data; + int ret, data; + + ret = read_poll_timeout(smn_read_register, data, data > 0 && data & MBOX_READY_MASK, + MBOX_DELAY_US, ACP_PSP_TIMEOUT_US, false, MP0_C2PMSG_114_REG); - ret = read_poll_timeout(smn_read, data, data & MBOX_READY_MASK, MBOX_DELAY_US, - ACP_PSP_TIMEOUT_US, false, adata->smn_dev, MP0_C2PMSG_114_REG); if (!ret) return 0; @@ -241,8 +227,8 @@ static int psp_send_cmd(struct acp_dev_data *adata, int cmd) return -EINVAL; /* Get a non-zero Doorbell value from PSP */ - ret = read_poll_timeout(smn_read, data, data, MBOX_DELAY_US, ACP_PSP_TIMEOUT_US, false, - adata->smn_dev, MP0_C2PMSG_73_REG); + ret = read_poll_timeout(smn_read_register, data, data > 0, MBOX_DELAY_US, + ACP_PSP_TIMEOUT_US, false, MP0_C2PMSG_73_REG); if (ret) { dev_err(sdev->dev, "Failed to get Doorbell from MBOX %x\n", MP0_C2PMSG_73_REG); @@ -254,10 +240,14 @@ static int psp_send_cmd(struct acp_dev_data *adata, int cmd) if (ret) return ret; - smn_write(adata->smn_dev, MP0_C2PMSG_114_REG, cmd); + ret = amd_smn_write(0, MP0_C2PMSG_114_REG, cmd); + if (ret) + return ret; /* Ring the Doorbell for PSP */ - smn_write(adata->smn_dev, MP0_C2PMSG_73_REG, data); + ret = amd_smn_write(0, MP0_C2PMSG_73_REG, data); + if (ret) + return ret; /* Check MBOX ready as PSP ack */ ret = psp_mbox_ready(adata, 1); @@ -348,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: @@ -395,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; @@ -427,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) { @@ -465,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; @@ -498,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; @@ -519,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; @@ -540,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; } @@ -578,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"); @@ -589,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) @@ -628,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; @@ -649,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"); @@ -771,16 +862,10 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) adata->pci_rev = pci->revision; mutex_init(&adata->acp_lock); sdev->pdata->hw_pdata = adata; - adata->smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, chip->host_bridge_id, NULL); - if (!adata->smn_dev) { - dev_err(sdev->dev, "Failed to get host bridge device\n"); - ret = -ENODEV; - goto unregister_dev; - } ret = acp_init(sdev); if (ret < 0) - goto free_smn_dev; + goto unregister_dev; sdev->ipc_irq = pci->irq; ret = request_threaded_irq(sdev->ipc_irq, acp_irq_handler, acp_irq_thread, @@ -788,7 +873,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "failed to register IRQ %d\n", sdev->ipc_irq); - goto free_smn_dev; + goto unregister_dev; } /* scan SoundWire capabilities exposed by DSDT */ @@ -801,7 +886,6 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: SoundWire probe error\n"); free_irq(sdev->ipc_irq, sdev); - pci_dev_put(adata->smn_dev); return ret; } @@ -847,8 +931,6 @@ skip_soundwire: free_ipc_irq: free_irq(sdev->ipc_irq, sdev); -free_smn_dev: - pci_dev_put(adata->smn_dev); unregister_dev: platform_device_unregister(adata->dmic_dev); return ret; @@ -859,9 +941,6 @@ void amd_sof_acp_remove(struct snd_sof_dev *sdev) { struct acp_dev_data *adata = sdev->pdata->hw_pdata; - if (adata->smn_dev) - pci_dev_put(adata->smn_dev); - if (adata->sdw) amd_sof_sdw_exit(sdev); |