162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0+ */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AMD ALSA SoC PCM Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2021 Advanced Micro Devices, Inc. All rights reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "vg_chip_offset_byte.h"
962306a36Sopenharmony_ci#include <sound/pcm.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define ACP5x_PHY_BASE_ADDRESS 0x1240000
1262306a36Sopenharmony_ci#define ACP_DEVICE_ID 0x15E2
1362306a36Sopenharmony_ci#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK	0x00010001
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define ACP_PGFSM_CNTL_POWER_ON_MASK	0x01
1662306a36Sopenharmony_ci#define ACP_PGFSM_CNTL_POWER_OFF_MASK	0x00
1762306a36Sopenharmony_ci#define ACP_PGFSM_STATUS_MASK		0x03
1862306a36Sopenharmony_ci#define ACP_POWERED_ON			0x00
1962306a36Sopenharmony_ci#define ACP_POWER_ON_IN_PROGRESS	0x01
2062306a36Sopenharmony_ci#define ACP_POWERED_OFF			0x02
2162306a36Sopenharmony_ci#define ACP_POWER_OFF_IN_PROGRESS	0x03
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define ACP_ERR_INTR_MASK	0x20000000
2462306a36Sopenharmony_ci#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define ACP5x_DEVS 4
2762306a36Sopenharmony_ci#define	ACP5x_REG_START	0x1240000
2862306a36Sopenharmony_ci#define	ACP5x_REG_END	0x1250200
2962306a36Sopenharmony_ci#define ACP5x_I2STDM_REG_START	0x1242400
3062306a36Sopenharmony_ci#define ACP5x_I2STDM_REG_END	0x1242410
3162306a36Sopenharmony_ci#define ACP5x_HS_TDM_REG_START	0x1242814
3262306a36Sopenharmony_ci#define ACP5x_HS_TDM_REG_END	0x1242824
3362306a36Sopenharmony_ci#define I2S_MODE 0
3462306a36Sopenharmony_ci#define ACP5x_I2S_MODE 1
3562306a36Sopenharmony_ci#define ACP5x_RES 4
3662306a36Sopenharmony_ci#define	I2S_RX_THRESHOLD 27
3762306a36Sopenharmony_ci#define	I2S_TX_THRESHOLD 28
3862306a36Sopenharmony_ci#define	HS_TX_THRESHOLD 24
3962306a36Sopenharmony_ci#define	HS_RX_THRESHOLD 23
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define I2S_SP_INSTANCE                 1
4262306a36Sopenharmony_ci#define I2S_HS_INSTANCE                 2
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define ACP_SRAM_PTE_OFFSET	0x02050000
4562306a36Sopenharmony_ci#define ACP_SRAM_SP_PB_PTE_OFFSET	0x0
4662306a36Sopenharmony_ci#define ACP_SRAM_SP_CP_PTE_OFFSET	0x100
4762306a36Sopenharmony_ci#define ACP_SRAM_HS_PB_PTE_OFFSET	0x200
4862306a36Sopenharmony_ci#define ACP_SRAM_HS_CP_PTE_OFFSET	0x300
4962306a36Sopenharmony_ci#define PAGE_SIZE_4K_ENABLE 0x2
5062306a36Sopenharmony_ci#define I2S_SP_TX_MEM_WINDOW_START	0x4000000
5162306a36Sopenharmony_ci#define I2S_SP_RX_MEM_WINDOW_START	0x4020000
5262306a36Sopenharmony_ci#define I2S_HS_TX_MEM_WINDOW_START	0x4040000
5362306a36Sopenharmony_ci#define I2S_HS_RX_MEM_WINDOW_START	0x4060000
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define SP_PB_FIFO_ADDR_OFFSET		0x500
5662306a36Sopenharmony_ci#define SP_CAPT_FIFO_ADDR_OFFSET	0x700
5762306a36Sopenharmony_ci#define HS_PB_FIFO_ADDR_OFFSET		0x900
5862306a36Sopenharmony_ci#define HS_CAPT_FIFO_ADDR_OFFSET	0xB00
5962306a36Sopenharmony_ci#define PLAYBACK_MIN_NUM_PERIODS    2
6062306a36Sopenharmony_ci#define PLAYBACK_MAX_NUM_PERIODS    8
6162306a36Sopenharmony_ci#define PLAYBACK_MAX_PERIOD_SIZE    8192
6262306a36Sopenharmony_ci#define PLAYBACK_MIN_PERIOD_SIZE    1024
6362306a36Sopenharmony_ci#define CAPTURE_MIN_NUM_PERIODS     2
6462306a36Sopenharmony_ci#define CAPTURE_MAX_NUM_PERIODS     8
6562306a36Sopenharmony_ci#define CAPTURE_MAX_PERIOD_SIZE     8192
6662306a36Sopenharmony_ci#define CAPTURE_MIN_PERIOD_SIZE     1024
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
6962306a36Sopenharmony_ci#define MIN_BUFFER MAX_BUFFER
7062306a36Sopenharmony_ci#define FIFO_SIZE 0x100
7162306a36Sopenharmony_ci#define DMA_SIZE 0x40
7262306a36Sopenharmony_ci#define FRM_LEN 0x100
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#define I2S_MASTER_MODE_ENABLE 1
7562306a36Sopenharmony_ci#define I2S_MASTER_MODE_DISABLE 0
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define SLOT_WIDTH_8 8
7862306a36Sopenharmony_ci#define SLOT_WIDTH_16 16
7962306a36Sopenharmony_ci#define SLOT_WIDTH_24 24
8062306a36Sopenharmony_ci#define SLOT_WIDTH_32 32
8162306a36Sopenharmony_ci#define TDM_ENABLE 1
8262306a36Sopenharmony_ci#define TDM_DISABLE 0
8362306a36Sopenharmony_ci#define ACP5x_ITER_IRER_SAMP_LEN_MASK	0x38
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistruct i2s_dev_data {
8662306a36Sopenharmony_ci	bool tdm_mode;
8762306a36Sopenharmony_ci	bool master_mode;
8862306a36Sopenharmony_ci	int i2s_irq;
8962306a36Sopenharmony_ci	u16 i2s_instance;
9062306a36Sopenharmony_ci	u32 tdm_fmt;
9162306a36Sopenharmony_ci	void __iomem *acp5x_base;
9262306a36Sopenharmony_ci	struct snd_pcm_substream *play_stream;
9362306a36Sopenharmony_ci	struct snd_pcm_substream *capture_stream;
9462306a36Sopenharmony_ci	struct snd_pcm_substream *i2ssp_play_stream;
9562306a36Sopenharmony_ci	struct snd_pcm_substream *i2ssp_capture_stream;
9662306a36Sopenharmony_ci};
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistruct i2s_stream_instance {
9962306a36Sopenharmony_ci	u16 num_pages;
10062306a36Sopenharmony_ci	u16 i2s_instance;
10162306a36Sopenharmony_ci	u16 direction;
10262306a36Sopenharmony_ci	u16 channels;
10362306a36Sopenharmony_ci	u32 xfer_resolution;
10462306a36Sopenharmony_ci	u32 val;
10562306a36Sopenharmony_ci	dma_addr_t dma_addr;
10662306a36Sopenharmony_ci	u64 bytescount;
10762306a36Sopenharmony_ci	void __iomem *acp5x_base;
10862306a36Sopenharmony_ci	u32 lrclk_div;
10962306a36Sopenharmony_ci	u32 bclk_div;
11062306a36Sopenharmony_ci};
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ciunion acp_dma_count {
11362306a36Sopenharmony_ci	struct {
11462306a36Sopenharmony_ci		u32 low;
11562306a36Sopenharmony_ci		u32 high;
11662306a36Sopenharmony_ci	} bcount;
11762306a36Sopenharmony_ci	u64 bytescount;
11862306a36Sopenharmony_ci};
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistruct acp5x_platform_info {
12162306a36Sopenharmony_ci	u16 play_i2s_instance;
12262306a36Sopenharmony_ci	u16 cap_i2s_instance;
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ciunion acp_i2stdm_mstrclkgen {
12662306a36Sopenharmony_ci	struct {
12762306a36Sopenharmony_ci		u32 i2stdm_master_mode : 1;
12862306a36Sopenharmony_ci		u32 i2stdm_format_mode : 1;
12962306a36Sopenharmony_ci		u32 i2stdm_lrclk_div_val : 9;
13062306a36Sopenharmony_ci		u32 i2stdm_bclk_div_val : 11;
13162306a36Sopenharmony_ci		u32:10;
13262306a36Sopenharmony_ci	} bitfields, bits;
13362306a36Sopenharmony_ci	u32  u32_all;
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/* common header file uses exact offset rather than relative
13762306a36Sopenharmony_ci * offset which requires subtraction logic from base_addr
13862306a36Sopenharmony_ci * for accessing ACP5x MMIO space registers
13962306a36Sopenharmony_ci */
14062306a36Sopenharmony_cistatic inline u32 acp_readl(void __iomem *base_addr)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	return readl(base_addr - ACP5x_PHY_BASE_ADDRESS);
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic inline void acp_writel(u32 val, void __iomem *base_addr)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	writel(val, base_addr - ACP5x_PHY_BASE_ADDRESS);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ciint snd_amd_acp_find_config(struct pci_dev *pci);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic inline u64 acp_get_byte_count(struct i2s_stream_instance *rtd,
15362306a36Sopenharmony_ci				     int direction)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	union acp_dma_count byte_count;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
15862306a36Sopenharmony_ci		switch (rtd->i2s_instance) {
15962306a36Sopenharmony_ci		case I2S_HS_INSTANCE:
16062306a36Sopenharmony_ci			byte_count.bcount.high =
16162306a36Sopenharmony_ci				acp_readl(rtd->acp5x_base +
16262306a36Sopenharmony_ci					  ACP_HS_TX_LINEARPOSCNTR_HIGH);
16362306a36Sopenharmony_ci			byte_count.bcount.low =
16462306a36Sopenharmony_ci				acp_readl(rtd->acp5x_base +
16562306a36Sopenharmony_ci					  ACP_HS_TX_LINEARPOSCNTR_LOW);
16662306a36Sopenharmony_ci			break;
16762306a36Sopenharmony_ci		case I2S_SP_INSTANCE:
16862306a36Sopenharmony_ci		default:
16962306a36Sopenharmony_ci			byte_count.bcount.high =
17062306a36Sopenharmony_ci				acp_readl(rtd->acp5x_base +
17162306a36Sopenharmony_ci					  ACP_I2S_TX_LINEARPOSCNTR_HIGH);
17262306a36Sopenharmony_ci			byte_count.bcount.low =
17362306a36Sopenharmony_ci				acp_readl(rtd->acp5x_base +
17462306a36Sopenharmony_ci					  ACP_I2S_TX_LINEARPOSCNTR_LOW);
17562306a36Sopenharmony_ci		}
17662306a36Sopenharmony_ci	} else {
17762306a36Sopenharmony_ci		switch (rtd->i2s_instance) {
17862306a36Sopenharmony_ci		case I2S_HS_INSTANCE:
17962306a36Sopenharmony_ci			byte_count.bcount.high =
18062306a36Sopenharmony_ci				acp_readl(rtd->acp5x_base +
18162306a36Sopenharmony_ci					  ACP_HS_RX_LINEARPOSCNTR_HIGH);
18262306a36Sopenharmony_ci			byte_count.bcount.low =
18362306a36Sopenharmony_ci				acp_readl(rtd->acp5x_base +
18462306a36Sopenharmony_ci					  ACP_HS_RX_LINEARPOSCNTR_LOW);
18562306a36Sopenharmony_ci			break;
18662306a36Sopenharmony_ci		case I2S_SP_INSTANCE:
18762306a36Sopenharmony_ci		default:
18862306a36Sopenharmony_ci			byte_count.bcount.high =
18962306a36Sopenharmony_ci				acp_readl(rtd->acp5x_base +
19062306a36Sopenharmony_ci					  ACP_I2S_RX_LINEARPOSCNTR_HIGH);
19162306a36Sopenharmony_ci			byte_count.bcount.low =
19262306a36Sopenharmony_ci				acp_readl(rtd->acp5x_base +
19362306a36Sopenharmony_ci					  ACP_I2S_RX_LINEARPOSCNTR_LOW);
19462306a36Sopenharmony_ci		}
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci	return byte_count.bytescount;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic inline void acp5x_set_i2s_clk(struct i2s_dev_data *adata,
20062306a36Sopenharmony_ci				     struct i2s_stream_instance *rtd)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	union acp_i2stdm_mstrclkgen mclkgen;
20362306a36Sopenharmony_ci	u32 master_reg;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	switch (rtd->i2s_instance) {
20662306a36Sopenharmony_ci	case I2S_HS_INSTANCE:
20762306a36Sopenharmony_ci		master_reg = ACP_I2STDM2_MSTRCLKGEN;
20862306a36Sopenharmony_ci		break;
20962306a36Sopenharmony_ci	case I2S_SP_INSTANCE:
21062306a36Sopenharmony_ci	default:
21162306a36Sopenharmony_ci		master_reg = ACP_I2STDM0_MSTRCLKGEN;
21262306a36Sopenharmony_ci		break;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	mclkgen.bits.i2stdm_master_mode = 0x1;
21662306a36Sopenharmony_ci	if (adata->tdm_mode)
21762306a36Sopenharmony_ci		mclkgen.bits.i2stdm_format_mode = 0x01;
21862306a36Sopenharmony_ci	else
21962306a36Sopenharmony_ci		mclkgen.bits.i2stdm_format_mode = 0x00;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	mclkgen.bits.i2stdm_bclk_div_val = rtd->bclk_div;
22262306a36Sopenharmony_ci	mclkgen.bits.i2stdm_lrclk_div_val = rtd->lrclk_div;
22362306a36Sopenharmony_ci	acp_writel(mclkgen.u32_all, rtd->acp5x_base + master_reg);
22462306a36Sopenharmony_ci}
225