Unverified Commit fe65ce84 authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: SOF: amd: add soundwire IO support for ACP7.0 &

Merge series from Vijendar Mukunda <Vijendar.Mukunda@amd.com>:

This patch series contains
- ACP sof stack improvements
- Add support for ACP7.1 platform.
- Soundwire IO support for ACP7.0 & ACP7.1 platforms

Link: https://github.com/thesofproject/linux/pull/5392
parents d85d055e e68074c6
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
@@ -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
+118 −15
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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:
@@ -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;
@@ -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) {
@@ -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;
@@ -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;
@@ -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;

@@ -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;
}

@@ -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");
@@ -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)
@@ -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;
@@ -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");

+7 −0
Original line number Diff line number Diff line
@@ -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
@@ -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,
@@ -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;
};

+9 −1
Original line number Diff line number Diff line
@@ -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,
};
@@ -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)