162306a36Sopenharmony_ci/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or
462306a36Sopenharmony_ci * redistributing this file, you may do so under either license.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright(c) 2021 Advanced Micro Devices, Inc. All rights reserved.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Author: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#ifndef __AMD_ACP_H
1262306a36Sopenharmony_ci#define __AMD_ACP_H
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <sound/pcm.h>
1562306a36Sopenharmony_ci#include <sound/soc.h>
1662306a36Sopenharmony_ci#include <sound/soc-acpi.h>
1762306a36Sopenharmony_ci#include <sound/soc-dai.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "chip_offset_byte.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define ACP3X_DEV			3
2262306a36Sopenharmony_ci#define ACP6X_DEV			6
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define DMIC_INSTANCE			0x00
2562306a36Sopenharmony_ci#define I2S_SP_INSTANCE			0x01
2662306a36Sopenharmony_ci#define I2S_BT_INSTANCE			0x02
2762306a36Sopenharmony_ci#define I2S_HS_INSTANCE			0x03
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define MEM_WINDOW_START		0x4080000
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define ACP_I2S_REG_START		0x1242400
3262306a36Sopenharmony_ci#define ACP_I2S_REG_END			0x1242810
3362306a36Sopenharmony_ci#define ACP3x_I2STDM_REG_START		0x1242400
3462306a36Sopenharmony_ci#define ACP3x_I2STDM_REG_END		0x1242410
3562306a36Sopenharmony_ci#define ACP3x_BT_TDM_REG_START		0x1242800
3662306a36Sopenharmony_ci#define ACP3x_BT_TDM_REG_END		0x1242810
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define THRESHOLD(bit, base)	((bit) + (base))
3962306a36Sopenharmony_ci#define I2S_RX_THRESHOLD(base)	THRESHOLD(7, base)
4062306a36Sopenharmony_ci#define I2S_TX_THRESHOLD(base)	THRESHOLD(8, base)
4162306a36Sopenharmony_ci#define BT_TX_THRESHOLD(base)	THRESHOLD(6, base)
4262306a36Sopenharmony_ci#define BT_RX_THRESHOLD(base)	THRESHOLD(5, base)
4362306a36Sopenharmony_ci#define HS_TX_THRESHOLD(base)	THRESHOLD(4, base)
4462306a36Sopenharmony_ci#define HS_RX_THRESHOLD(base)	THRESHOLD(3, base)
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define ACP_SRAM_SP_PB_PTE_OFFSET	0x0
4762306a36Sopenharmony_ci#define ACP_SRAM_SP_CP_PTE_OFFSET	0x100
4862306a36Sopenharmony_ci#define ACP_SRAM_BT_PB_PTE_OFFSET	0x200
4962306a36Sopenharmony_ci#define ACP_SRAM_BT_CP_PTE_OFFSET	0x300
5062306a36Sopenharmony_ci#define ACP_SRAM_PDM_PTE_OFFSET		0x400
5162306a36Sopenharmony_ci#define ACP_SRAM_HS_PB_PTE_OFFSET       0x500
5262306a36Sopenharmony_ci#define ACP_SRAM_HS_CP_PTE_OFFSET       0x600
5362306a36Sopenharmony_ci#define PAGE_SIZE_4K_ENABLE		0x2
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define I2S_SP_TX_MEM_WINDOW_START	0x4000000
5662306a36Sopenharmony_ci#define I2S_SP_RX_MEM_WINDOW_START	0x4020000
5762306a36Sopenharmony_ci#define I2S_BT_TX_MEM_WINDOW_START	0x4040000
5862306a36Sopenharmony_ci#define I2S_BT_RX_MEM_WINDOW_START	0x4060000
5962306a36Sopenharmony_ci#define I2S_HS_TX_MEM_WINDOW_START      0x40A0000
6062306a36Sopenharmony_ci#define I2S_HS_RX_MEM_WINDOW_START      0x40C0000
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define SP_PB_FIFO_ADDR_OFFSET		0x500
6362306a36Sopenharmony_ci#define SP_CAPT_FIFO_ADDR_OFFSET	0x700
6462306a36Sopenharmony_ci#define BT_PB_FIFO_ADDR_OFFSET		0x900
6562306a36Sopenharmony_ci#define BT_CAPT_FIFO_ADDR_OFFSET	0xB00
6662306a36Sopenharmony_ci#define HS_PB_FIFO_ADDR_OFFSET		0xD00
6762306a36Sopenharmony_ci#define HS_CAPT_FIFO_ADDR_OFFSET	0xF00
6862306a36Sopenharmony_ci#define PLAYBACK_MIN_NUM_PERIODS	2
6962306a36Sopenharmony_ci#define PLAYBACK_MAX_NUM_PERIODS	8
7062306a36Sopenharmony_ci#define PLAYBACK_MAX_PERIOD_SIZE	8192
7162306a36Sopenharmony_ci#define PLAYBACK_MIN_PERIOD_SIZE	1024
7262306a36Sopenharmony_ci#define CAPTURE_MIN_NUM_PERIODS		2
7362306a36Sopenharmony_ci#define CAPTURE_MAX_NUM_PERIODS		8
7462306a36Sopenharmony_ci#define CAPTURE_MAX_PERIOD_SIZE		8192
7562306a36Sopenharmony_ci#define CAPTURE_MIN_PERIOD_SIZE		1024
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define MAX_BUFFER			65536
7862306a36Sopenharmony_ci#define MIN_BUFFER			MAX_BUFFER
7962306a36Sopenharmony_ci#define FIFO_SIZE			0x100
8062306a36Sopenharmony_ci#define DMA_SIZE			0x40
8162306a36Sopenharmony_ci#define FRM_LEN				0x100
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci#define ACP3x_ITER_IRER_SAMP_LEN_MASK	0x38
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define ACP_MAX_STREAM			8
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci#define TDM_ENABLE	1
8862306a36Sopenharmony_ci#define TDM_DISABLE	0
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#define SLOT_WIDTH_8	0x8
9162306a36Sopenharmony_ci#define SLOT_WIDTH_16	0x10
9262306a36Sopenharmony_ci#define SLOT_WIDTH_24	0x18
9362306a36Sopenharmony_ci#define SLOT_WIDTH_32	0x20
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define ACP6X_PGFSM_CONTROL                     0x1024
9662306a36Sopenharmony_ci#define ACP6X_PGFSM_STATUS                      0x1028
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define ACP_SOFT_RST_DONE_MASK	0x00010001
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define ACP_PGFSM_CNTL_POWER_ON_MASK            0x01
10162306a36Sopenharmony_ci#define ACP_PGFSM_CNTL_POWER_OFF_MASK           0x00
10262306a36Sopenharmony_ci#define ACP_PGFSM_STATUS_MASK                   0x03
10362306a36Sopenharmony_ci#define ACP_POWERED_ON                          0x00
10462306a36Sopenharmony_ci#define ACP_POWER_ON_IN_PROGRESS                0x01
10562306a36Sopenharmony_ci#define ACP_POWERED_OFF                         0x02
10662306a36Sopenharmony_ci#define ACP_POWER_OFF_IN_PROGRESS               0x03
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define ACP_ERROR_MASK                          0x20000000
10962306a36Sopenharmony_ci#define ACP_EXT_INTR_STAT_CLEAR_MASK            0xffffffff
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define ACP_TIMEOUT		500
11262306a36Sopenharmony_ci#define DELAY_US		5
11362306a36Sopenharmony_ci#define ACP_SUSPEND_DELAY_MS   2000
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci#define PDM_DMA_STAT            0x10
11662306a36Sopenharmony_ci#define PDM_DMA_INTR_MASK       0x10000
11762306a36Sopenharmony_ci#define PDM_DEC_64              0x2
11862306a36Sopenharmony_ci#define PDM_CLK_FREQ_MASK       0x07
11962306a36Sopenharmony_ci#define PDM_MISC_CTRL_MASK      0x10
12062306a36Sopenharmony_ci#define PDM_ENABLE              0x01
12162306a36Sopenharmony_ci#define PDM_DISABLE             0x00
12262306a36Sopenharmony_ci#define DMA_EN_MASK             0x02
12362306a36Sopenharmony_ci#define DELAY_US                5
12462306a36Sopenharmony_ci#define PDM_TIMEOUT             1000
12562306a36Sopenharmony_ci#define ACP_REGION2_OFFSET      0x02000000
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistruct acp_chip_info {
12862306a36Sopenharmony_ci	char *name;		/* Platform name */
12962306a36Sopenharmony_ci	unsigned int acp_rev;	/* ACP Revision id */
13062306a36Sopenharmony_ci	void __iomem *base;	/* ACP memory PCI base */
13162306a36Sopenharmony_ci	struct platform_device *chip_pdev;
13262306a36Sopenharmony_ci};
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistruct acp_stream {
13562306a36Sopenharmony_ci	struct list_head list;
13662306a36Sopenharmony_ci	struct snd_pcm_substream *substream;
13762306a36Sopenharmony_ci	int irq_bit;
13862306a36Sopenharmony_ci	int dai_id;
13962306a36Sopenharmony_ci	int id;
14062306a36Sopenharmony_ci	int dir;
14162306a36Sopenharmony_ci	u64 bytescount;
14262306a36Sopenharmony_ci	u32 reg_offset;
14362306a36Sopenharmony_ci	u32 pte_offset;
14462306a36Sopenharmony_ci	u32 fifo_offset;
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistruct acp_resource {
14862306a36Sopenharmony_ci	int offset;
14962306a36Sopenharmony_ci	int no_of_ctrls;
15062306a36Sopenharmony_ci	int irqp_used;
15162306a36Sopenharmony_ci	bool soc_mclk;
15262306a36Sopenharmony_ci	u32 irq_reg_offset;
15362306a36Sopenharmony_ci	u32 i2s_pin_cfg_offset;
15462306a36Sopenharmony_ci	int i2s_mode;
15562306a36Sopenharmony_ci	u64 scratch_reg_offset;
15662306a36Sopenharmony_ci	u64 sram_pte_offset;
15762306a36Sopenharmony_ci};
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistruct acp_dev_data {
16062306a36Sopenharmony_ci	char *name;
16162306a36Sopenharmony_ci	struct device *dev;
16262306a36Sopenharmony_ci	void __iomem *acp_base;
16362306a36Sopenharmony_ci	unsigned int i2s_irq;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	bool tdm_mode;
16662306a36Sopenharmony_ci	/* SOC specific dais */
16762306a36Sopenharmony_ci	struct snd_soc_dai_driver *dai_driver;
16862306a36Sopenharmony_ci	int num_dai;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	struct list_head stream_list;
17162306a36Sopenharmony_ci	spinlock_t acp_lock;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	struct snd_soc_acpi_mach *machines;
17462306a36Sopenharmony_ci	struct platform_device *mach_dev;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	u32 bclk_div;
17762306a36Sopenharmony_ci	u32 lrclk_div;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	struct acp_resource *rsrc;
18062306a36Sopenharmony_ci	u32 ch_mask;
18162306a36Sopenharmony_ci	u32 tdm_tx_fmt[3];
18262306a36Sopenharmony_ci	u32 tdm_rx_fmt[3];
18362306a36Sopenharmony_ci	u32 xfer_tx_resolution[3];
18462306a36Sopenharmony_ci	u32 xfer_rx_resolution[3];
18562306a36Sopenharmony_ci};
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ciunion acp_i2stdm_mstrclkgen {
18862306a36Sopenharmony_ci	struct {
18962306a36Sopenharmony_ci		u32 i2stdm_master_mode : 1;
19062306a36Sopenharmony_ci		u32 i2stdm_format_mode : 1;
19162306a36Sopenharmony_ci		u32 i2stdm_lrclk_div_val : 9;
19262306a36Sopenharmony_ci		u32 i2stdm_bclk_div_val : 11;
19362306a36Sopenharmony_ci		u32:10;
19462306a36Sopenharmony_ci	} bitfields, bits;
19562306a36Sopenharmony_ci	u32  u32_all;
19662306a36Sopenharmony_ci};
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ciextern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops;
19962306a36Sopenharmony_ciextern const struct snd_soc_dai_ops acp_dmic_dai_ops;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ciint acp_platform_register(struct device *dev);
20262306a36Sopenharmony_ciint acp_platform_unregister(struct device *dev);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ciint acp_machine_select(struct acp_dev_data *adata);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ciint smn_read(struct pci_dev *dev, u32 smn_addr);
20762306a36Sopenharmony_ciint smn_write(struct pci_dev *dev, u32 smn_addr, u32 data);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ciint acp_init(struct acp_chip_info *chip);
21062306a36Sopenharmony_ciint acp_deinit(void __iomem *base);
21162306a36Sopenharmony_civoid acp_enable_interrupts(struct acp_dev_data *adata);
21262306a36Sopenharmony_civoid acp_disable_interrupts(struct acp_dev_data *adata);
21362306a36Sopenharmony_ci/* Machine configuration */
21462306a36Sopenharmony_ciint snd_amd_acp_find_config(struct pci_dev *pci);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_civoid config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream);
21762306a36Sopenharmony_civoid config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size);
21862306a36Sopenharmony_civoid restore_acp_pdm_params(struct snd_pcm_substream *substream,
21962306a36Sopenharmony_ci			    struct acp_dev_data *adata);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ciint restore_acp_i2s_params(struct snd_pcm_substream *substream,
22262306a36Sopenharmony_ci			   struct acp_dev_data *adata, struct acp_stream *stream);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int direction)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	u64 byte_count = 0, low = 0, high = 0;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
22962306a36Sopenharmony_ci		switch (dai_id) {
23062306a36Sopenharmony_ci		case I2S_BT_INSTANCE:
23162306a36Sopenharmony_ci			high = readl(adata->acp_base + ACP_BT_TX_LINEARPOSITIONCNTR_HIGH);
23262306a36Sopenharmony_ci			low = readl(adata->acp_base + ACP_BT_TX_LINEARPOSITIONCNTR_LOW);
23362306a36Sopenharmony_ci			break;
23462306a36Sopenharmony_ci		case I2S_SP_INSTANCE:
23562306a36Sopenharmony_ci			high = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH);
23662306a36Sopenharmony_ci			low = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_LOW);
23762306a36Sopenharmony_ci			break;
23862306a36Sopenharmony_ci		case I2S_HS_INSTANCE:
23962306a36Sopenharmony_ci			high = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_HIGH);
24062306a36Sopenharmony_ci			low = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_LOW);
24162306a36Sopenharmony_ci			break;
24262306a36Sopenharmony_ci		default:
24362306a36Sopenharmony_ci			dev_err(adata->dev, "Invalid dai id %x\n", dai_id);
24462306a36Sopenharmony_ci			goto POINTER_RETURN_BYTES;
24562306a36Sopenharmony_ci		}
24662306a36Sopenharmony_ci	} else {
24762306a36Sopenharmony_ci		switch (dai_id) {
24862306a36Sopenharmony_ci		case I2S_BT_INSTANCE:
24962306a36Sopenharmony_ci			high = readl(adata->acp_base + ACP_BT_RX_LINEARPOSITIONCNTR_HIGH);
25062306a36Sopenharmony_ci			low = readl(adata->acp_base + ACP_BT_RX_LINEARPOSITIONCNTR_LOW);
25162306a36Sopenharmony_ci			break;
25262306a36Sopenharmony_ci		case I2S_SP_INSTANCE:
25362306a36Sopenharmony_ci			high = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH);
25462306a36Sopenharmony_ci			low = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_LOW);
25562306a36Sopenharmony_ci			break;
25662306a36Sopenharmony_ci		case I2S_HS_INSTANCE:
25762306a36Sopenharmony_ci			high = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_HIGH);
25862306a36Sopenharmony_ci			low = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_LOW);
25962306a36Sopenharmony_ci			break;
26062306a36Sopenharmony_ci		case DMIC_INSTANCE:
26162306a36Sopenharmony_ci			high = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH);
26262306a36Sopenharmony_ci			low = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW);
26362306a36Sopenharmony_ci			break;
26462306a36Sopenharmony_ci		default:
26562306a36Sopenharmony_ci			dev_err(adata->dev, "Invalid dai id %x\n", dai_id);
26662306a36Sopenharmony_ci			goto POINTER_RETURN_BYTES;
26762306a36Sopenharmony_ci		}
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci	/* Get 64 bit value from two 32 bit registers */
27062306a36Sopenharmony_ci	byte_count = (high << 32) | low;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ciPOINTER_RETURN_BYTES:
27362306a36Sopenharmony_ci	return byte_count;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	union acp_i2stdm_mstrclkgen mclkgen;
27962306a36Sopenharmony_ci	u32 master_reg;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	switch (dai_id) {
28262306a36Sopenharmony_ci	case I2S_SP_INSTANCE:
28362306a36Sopenharmony_ci		master_reg = ACP_I2STDM0_MSTRCLKGEN;
28462306a36Sopenharmony_ci		break;
28562306a36Sopenharmony_ci	case I2S_BT_INSTANCE:
28662306a36Sopenharmony_ci		master_reg = ACP_I2STDM1_MSTRCLKGEN;
28762306a36Sopenharmony_ci		break;
28862306a36Sopenharmony_ci	case I2S_HS_INSTANCE:
28962306a36Sopenharmony_ci		master_reg = ACP_I2STDM2_MSTRCLKGEN;
29062306a36Sopenharmony_ci		break;
29162306a36Sopenharmony_ci	default:
29262306a36Sopenharmony_ci		master_reg = ACP_I2STDM0_MSTRCLKGEN;
29362306a36Sopenharmony_ci		break;
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	mclkgen.bits.i2stdm_master_mode = 0x1;
29762306a36Sopenharmony_ci	mclkgen.bits.i2stdm_format_mode = 0x00;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	mclkgen.bits.i2stdm_bclk_div_val = adata->bclk_div;
30062306a36Sopenharmony_ci	mclkgen.bits.i2stdm_lrclk_div_val = adata->lrclk_div;
30162306a36Sopenharmony_ci	writel(mclkgen.u32_all, adata->acp_base + master_reg);
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci#endif
304