18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2015 Advanced Micro Devices, Inc.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * Authors: AMD
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <linux/irqdomain.h>
278c2ecf20Sopenharmony_ci#include <linux/pci.h>
288c2ecf20Sopenharmony_ci#include <linux/pm_domain.h>
298c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
308c2ecf20Sopenharmony_ci#include <sound/designware_i2s.h>
318c2ecf20Sopenharmony_ci#include <sound/pcm.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include "amdgpu.h"
348c2ecf20Sopenharmony_ci#include "atom.h"
358c2ecf20Sopenharmony_ci#include "amdgpu_acp.h"
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include "acp_gfx_if.h"
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define ACP_TILE_ON_MASK                	0x03
408c2ecf20Sopenharmony_ci#define ACP_TILE_OFF_MASK               	0x02
418c2ecf20Sopenharmony_ci#define ACP_TILE_ON_RETAIN_REG_MASK     	0x1f
428c2ecf20Sopenharmony_ci#define ACP_TILE_OFF_RETAIN_REG_MASK    	0x20
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define ACP_TILE_P1_MASK                	0x3e
458c2ecf20Sopenharmony_ci#define ACP_TILE_P2_MASK                	0x3d
468c2ecf20Sopenharmony_ci#define ACP_TILE_DSP0_MASK              	0x3b
478c2ecf20Sopenharmony_ci#define ACP_TILE_DSP1_MASK              	0x37
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define ACP_TILE_DSP2_MASK              	0x2f
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define ACP_DMA_REGS_END			0x146c0
528c2ecf20Sopenharmony_ci#define ACP_I2S_PLAY_REGS_START			0x14840
538c2ecf20Sopenharmony_ci#define ACP_I2S_PLAY_REGS_END			0x148b4
548c2ecf20Sopenharmony_ci#define ACP_I2S_CAP_REGS_START			0x148b8
558c2ecf20Sopenharmony_ci#define ACP_I2S_CAP_REGS_END			0x1496c
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define ACP_I2S_COMP1_CAP_REG_OFFSET		0xac
588c2ecf20Sopenharmony_ci#define ACP_I2S_COMP2_CAP_REG_OFFSET		0xa8
598c2ecf20Sopenharmony_ci#define ACP_I2S_COMP1_PLAY_REG_OFFSET		0x6c
608c2ecf20Sopenharmony_ci#define ACP_I2S_COMP2_PLAY_REG_OFFSET		0x68
618c2ecf20Sopenharmony_ci#define ACP_BT_PLAY_REGS_START			0x14970
628c2ecf20Sopenharmony_ci#define ACP_BT_PLAY_REGS_END			0x14a24
638c2ecf20Sopenharmony_ci#define ACP_BT_COMP1_REG_OFFSET			0xac
648c2ecf20Sopenharmony_ci#define ACP_BT_COMP2_REG_OFFSET			0xa8
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define mmACP_PGFSM_RETAIN_REG			0x51c9
678c2ecf20Sopenharmony_ci#define mmACP_PGFSM_CONFIG_REG			0x51ca
688c2ecf20Sopenharmony_ci#define mmACP_PGFSM_READ_REG_0			0x51cc
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#define mmACP_MEM_SHUT_DOWN_REQ_LO		0x51f8
718c2ecf20Sopenharmony_ci#define mmACP_MEM_SHUT_DOWN_REQ_HI		0x51f9
728c2ecf20Sopenharmony_ci#define mmACP_MEM_SHUT_DOWN_STS_LO		0x51fa
738c2ecf20Sopenharmony_ci#define mmACP_MEM_SHUT_DOWN_STS_HI		0x51fb
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#define mmACP_CONTROL				0x5131
768c2ecf20Sopenharmony_ci#define mmACP_STATUS				0x5133
778c2ecf20Sopenharmony_ci#define mmACP_SOFT_RESET			0x5134
788c2ecf20Sopenharmony_ci#define ACP_CONTROL__ClkEn_MASK 		0x1
798c2ecf20Sopenharmony_ci#define ACP_SOFT_RESET__SoftResetAud_MASK 	0x100
808c2ecf20Sopenharmony_ci#define ACP_SOFT_RESET__SoftResetAudDone_MASK	0x1000000
818c2ecf20Sopenharmony_ci#define ACP_CLOCK_EN_TIME_OUT_VALUE		0x000000FF
828c2ecf20Sopenharmony_ci#define ACP_SOFT_RESET_DONE_TIME_OUT_VALUE	0x000000FF
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci#define ACP_TIMEOUT_LOOP			0x000000FF
858c2ecf20Sopenharmony_ci#define ACP_DEVS				4
868c2ecf20Sopenharmony_ci#define ACP_SRC_ID				162
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cienum {
898c2ecf20Sopenharmony_ci	ACP_TILE_P1 = 0,
908c2ecf20Sopenharmony_ci	ACP_TILE_P2,
918c2ecf20Sopenharmony_ci	ACP_TILE_DSP0,
928c2ecf20Sopenharmony_ci	ACP_TILE_DSP1,
938c2ecf20Sopenharmony_ci	ACP_TILE_DSP2,
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic int acp_sw_init(void *handle)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	adev->acp.parent = adev->dev;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	adev->acp.cgs_device =
1038c2ecf20Sopenharmony_ci		amdgpu_cgs_create_device(adev);
1048c2ecf20Sopenharmony_ci	if (!adev->acp.cgs_device)
1058c2ecf20Sopenharmony_ci		return -EINVAL;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	return 0;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic int acp_sw_fini(void *handle)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (adev->acp.cgs_device)
1158c2ecf20Sopenharmony_ci		amdgpu_cgs_destroy_device(adev->acp.cgs_device);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return 0;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistruct acp_pm_domain {
1218c2ecf20Sopenharmony_ci	void *adev;
1228c2ecf20Sopenharmony_ci	struct generic_pm_domain gpd;
1238c2ecf20Sopenharmony_ci};
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic int acp_poweroff(struct generic_pm_domain *genpd)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct acp_pm_domain *apd;
1288c2ecf20Sopenharmony_ci	struct amdgpu_device *adev;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	apd = container_of(genpd, struct acp_pm_domain, gpd);
1318c2ecf20Sopenharmony_ci	if (apd != NULL) {
1328c2ecf20Sopenharmony_ci		adev = apd->adev;
1338c2ecf20Sopenharmony_ci	/* call smu to POWER GATE ACP block
1348c2ecf20Sopenharmony_ci	 * smu will
1358c2ecf20Sopenharmony_ci	 * 1. turn off the acp clock
1368c2ecf20Sopenharmony_ci	 * 2. power off the acp tiles
1378c2ecf20Sopenharmony_ci	 * 3. check and enter ulv state
1388c2ecf20Sopenharmony_ci	 */
1398c2ecf20Sopenharmony_ci		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci	return 0;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic int acp_poweron(struct generic_pm_domain *genpd)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	struct acp_pm_domain *apd;
1478c2ecf20Sopenharmony_ci	struct amdgpu_device *adev;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	apd = container_of(genpd, struct acp_pm_domain, gpd);
1508c2ecf20Sopenharmony_ci	if (apd != NULL) {
1518c2ecf20Sopenharmony_ci		adev = apd->adev;
1528c2ecf20Sopenharmony_ci	/* call smu to UNGATE ACP block
1538c2ecf20Sopenharmony_ci	 * smu will
1548c2ecf20Sopenharmony_ci	 * 1. exit ulv
1558c2ecf20Sopenharmony_ci	 * 2. turn on acp clock
1568c2ecf20Sopenharmony_ci	 * 3. power on acp tiles
1578c2ecf20Sopenharmony_ci	 */
1588c2ecf20Sopenharmony_ci		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci	return 0;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic int acp_genpd_add_device(struct device *dev, void *data)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	struct generic_pm_domain *gpd = data;
1668c2ecf20Sopenharmony_ci	int ret;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	ret = pm_genpd_add_device(gpd, dev);
1698c2ecf20Sopenharmony_ci	if (ret)
1708c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to add dev to genpd %d\n", ret);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	return ret;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic int acp_genpd_remove_device(struct device *dev, void *data)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	int ret;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	ret = pm_genpd_remove_device(dev);
1808c2ecf20Sopenharmony_ci	if (ret)
1818c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to remove dev from genpd %d\n", ret);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/* Continue to remove */
1848c2ecf20Sopenharmony_ci	return 0;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci/**
1888c2ecf20Sopenharmony_ci * acp_hw_init - start and test ACP block
1898c2ecf20Sopenharmony_ci *
1908c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
1918c2ecf20Sopenharmony_ci *
1928c2ecf20Sopenharmony_ci */
1938c2ecf20Sopenharmony_cistatic int acp_hw_init(void *handle)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	int r;
1968c2ecf20Sopenharmony_ci	uint64_t acp_base;
1978c2ecf20Sopenharmony_ci	u32 val = 0;
1988c2ecf20Sopenharmony_ci	u32 count = 0;
1998c2ecf20Sopenharmony_ci	struct i2s_platform_data *i2s_pdata = NULL;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	const struct amdgpu_ip_block *ip_block =
2048c2ecf20Sopenharmony_ci		amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_ACP);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	if (!ip_block)
2078c2ecf20Sopenharmony_ci		return -EINVAL;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	r = amd_acp_hw_init(adev->acp.cgs_device,
2108c2ecf20Sopenharmony_ci			    ip_block->version->major, ip_block->version->minor);
2118c2ecf20Sopenharmony_ci	/* -ENODEV means board uses AZ rather than ACP */
2128c2ecf20Sopenharmony_ci	if (r == -ENODEV) {
2138c2ecf20Sopenharmony_ci		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
2148c2ecf20Sopenharmony_ci		return 0;
2158c2ecf20Sopenharmony_ci	} else if (r) {
2168c2ecf20Sopenharmony_ci		return r;
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	if (adev->rmmio_size == 0 || adev->rmmio_size < 0x5289)
2208c2ecf20Sopenharmony_ci		return -EINVAL;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	acp_base = adev->rmmio_base;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	adev->acp.acp_genpd = kzalloc(sizeof(struct acp_pm_domain), GFP_KERNEL);
2268c2ecf20Sopenharmony_ci	if (adev->acp.acp_genpd == NULL)
2278c2ecf20Sopenharmony_ci		return -ENOMEM;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	adev->acp.acp_genpd->gpd.name = "ACP_AUDIO";
2308c2ecf20Sopenharmony_ci	adev->acp.acp_genpd->gpd.power_off = acp_poweroff;
2318c2ecf20Sopenharmony_ci	adev->acp.acp_genpd->gpd.power_on = acp_poweron;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	adev->acp.acp_genpd->adev = adev;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	pm_genpd_init(&adev->acp.acp_genpd->gpd, NULL, false);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	adev->acp.acp_cell = kcalloc(ACP_DEVS, sizeof(struct mfd_cell),
2398c2ecf20Sopenharmony_ci							GFP_KERNEL);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (adev->acp.acp_cell == NULL) {
2428c2ecf20Sopenharmony_ci		r = -ENOMEM;
2438c2ecf20Sopenharmony_ci		goto failure;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	adev->acp.acp_res = kcalloc(5, sizeof(struct resource), GFP_KERNEL);
2478c2ecf20Sopenharmony_ci	if (adev->acp.acp_res == NULL) {
2488c2ecf20Sopenharmony_ci		r = -ENOMEM;
2498c2ecf20Sopenharmony_ci		goto failure;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	i2s_pdata = kcalloc(3, sizeof(struct i2s_platform_data), GFP_KERNEL);
2538c2ecf20Sopenharmony_ci	if (i2s_pdata == NULL) {
2548c2ecf20Sopenharmony_ci		r = -ENOMEM;
2558c2ecf20Sopenharmony_ci		goto failure;
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	switch (adev->asic_type) {
2598c2ecf20Sopenharmony_ci	case CHIP_STONEY:
2608c2ecf20Sopenharmony_ci		i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
2618c2ecf20Sopenharmony_ci			DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
2628c2ecf20Sopenharmony_ci		break;
2638c2ecf20Sopenharmony_ci	default:
2648c2ecf20Sopenharmony_ci		i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci	i2s_pdata[0].cap = DWC_I2S_PLAY;
2678c2ecf20Sopenharmony_ci	i2s_pdata[0].snd_rates = SNDRV_PCM_RATE_8000_96000;
2688c2ecf20Sopenharmony_ci	i2s_pdata[0].i2s_reg_comp1 = ACP_I2S_COMP1_PLAY_REG_OFFSET;
2698c2ecf20Sopenharmony_ci	i2s_pdata[0].i2s_reg_comp2 = ACP_I2S_COMP2_PLAY_REG_OFFSET;
2708c2ecf20Sopenharmony_ci	switch (adev->asic_type) {
2718c2ecf20Sopenharmony_ci	case CHIP_STONEY:
2728c2ecf20Sopenharmony_ci		i2s_pdata[1].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
2738c2ecf20Sopenharmony_ci			DW_I2S_QUIRK_COMP_PARAM1 |
2748c2ecf20Sopenharmony_ci			DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
2758c2ecf20Sopenharmony_ci		break;
2768c2ecf20Sopenharmony_ci	default:
2778c2ecf20Sopenharmony_ci		i2s_pdata[1].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
2788c2ecf20Sopenharmony_ci			DW_I2S_QUIRK_COMP_PARAM1;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	i2s_pdata[1].cap = DWC_I2S_RECORD;
2828c2ecf20Sopenharmony_ci	i2s_pdata[1].snd_rates = SNDRV_PCM_RATE_8000_96000;
2838c2ecf20Sopenharmony_ci	i2s_pdata[1].i2s_reg_comp1 = ACP_I2S_COMP1_CAP_REG_OFFSET;
2848c2ecf20Sopenharmony_ci	i2s_pdata[1].i2s_reg_comp2 = ACP_I2S_COMP2_CAP_REG_OFFSET;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	i2s_pdata[2].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET;
2878c2ecf20Sopenharmony_ci	switch (adev->asic_type) {
2888c2ecf20Sopenharmony_ci	case CHIP_STONEY:
2898c2ecf20Sopenharmony_ci		i2s_pdata[2].quirks |= DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
2908c2ecf20Sopenharmony_ci		break;
2918c2ecf20Sopenharmony_ci	default:
2928c2ecf20Sopenharmony_ci		break;
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	i2s_pdata[2].cap = DWC_I2S_PLAY | DWC_I2S_RECORD;
2968c2ecf20Sopenharmony_ci	i2s_pdata[2].snd_rates = SNDRV_PCM_RATE_8000_96000;
2978c2ecf20Sopenharmony_ci	i2s_pdata[2].i2s_reg_comp1 = ACP_BT_COMP1_REG_OFFSET;
2988c2ecf20Sopenharmony_ci	i2s_pdata[2].i2s_reg_comp2 = ACP_BT_COMP2_REG_OFFSET;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	adev->acp.acp_res[0].name = "acp2x_dma";
3018c2ecf20Sopenharmony_ci	adev->acp.acp_res[0].flags = IORESOURCE_MEM;
3028c2ecf20Sopenharmony_ci	adev->acp.acp_res[0].start = acp_base;
3038c2ecf20Sopenharmony_ci	adev->acp.acp_res[0].end = acp_base + ACP_DMA_REGS_END;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	adev->acp.acp_res[1].name = "acp2x_dw_i2s_play";
3068c2ecf20Sopenharmony_ci	adev->acp.acp_res[1].flags = IORESOURCE_MEM;
3078c2ecf20Sopenharmony_ci	adev->acp.acp_res[1].start = acp_base + ACP_I2S_PLAY_REGS_START;
3088c2ecf20Sopenharmony_ci	adev->acp.acp_res[1].end = acp_base + ACP_I2S_PLAY_REGS_END;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	adev->acp.acp_res[2].name = "acp2x_dw_i2s_cap";
3118c2ecf20Sopenharmony_ci	adev->acp.acp_res[2].flags = IORESOURCE_MEM;
3128c2ecf20Sopenharmony_ci	adev->acp.acp_res[2].start = acp_base + ACP_I2S_CAP_REGS_START;
3138c2ecf20Sopenharmony_ci	adev->acp.acp_res[2].end = acp_base + ACP_I2S_CAP_REGS_END;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	adev->acp.acp_res[3].name = "acp2x_dw_bt_i2s_play_cap";
3168c2ecf20Sopenharmony_ci	adev->acp.acp_res[3].flags = IORESOURCE_MEM;
3178c2ecf20Sopenharmony_ci	adev->acp.acp_res[3].start = acp_base + ACP_BT_PLAY_REGS_START;
3188c2ecf20Sopenharmony_ci	adev->acp.acp_res[3].end = acp_base + ACP_BT_PLAY_REGS_END;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	adev->acp.acp_res[4].name = "acp2x_dma_irq";
3218c2ecf20Sopenharmony_ci	adev->acp.acp_res[4].flags = IORESOURCE_IRQ;
3228c2ecf20Sopenharmony_ci	adev->acp.acp_res[4].start = amdgpu_irq_create_mapping(adev, 162);
3238c2ecf20Sopenharmony_ci	adev->acp.acp_res[4].end = adev->acp.acp_res[4].start;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	adev->acp.acp_cell[0].name = "acp_audio_dma";
3268c2ecf20Sopenharmony_ci	adev->acp.acp_cell[0].num_resources = 5;
3278c2ecf20Sopenharmony_ci	adev->acp.acp_cell[0].resources = &adev->acp.acp_res[0];
3288c2ecf20Sopenharmony_ci	adev->acp.acp_cell[0].platform_data = &adev->asic_type;
3298c2ecf20Sopenharmony_ci	adev->acp.acp_cell[0].pdata_size = sizeof(adev->asic_type);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	adev->acp.acp_cell[1].name = "designware-i2s";
3328c2ecf20Sopenharmony_ci	adev->acp.acp_cell[1].num_resources = 1;
3338c2ecf20Sopenharmony_ci	adev->acp.acp_cell[1].resources = &adev->acp.acp_res[1];
3348c2ecf20Sopenharmony_ci	adev->acp.acp_cell[1].platform_data = &i2s_pdata[0];
3358c2ecf20Sopenharmony_ci	adev->acp.acp_cell[1].pdata_size = sizeof(struct i2s_platform_data);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	adev->acp.acp_cell[2].name = "designware-i2s";
3388c2ecf20Sopenharmony_ci	adev->acp.acp_cell[2].num_resources = 1;
3398c2ecf20Sopenharmony_ci	adev->acp.acp_cell[2].resources = &adev->acp.acp_res[2];
3408c2ecf20Sopenharmony_ci	adev->acp.acp_cell[2].platform_data = &i2s_pdata[1];
3418c2ecf20Sopenharmony_ci	adev->acp.acp_cell[2].pdata_size = sizeof(struct i2s_platform_data);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	adev->acp.acp_cell[3].name = "designware-i2s";
3448c2ecf20Sopenharmony_ci	adev->acp.acp_cell[3].num_resources = 1;
3458c2ecf20Sopenharmony_ci	adev->acp.acp_cell[3].resources = &adev->acp.acp_res[3];
3468c2ecf20Sopenharmony_ci	adev->acp.acp_cell[3].platform_data = &i2s_pdata[2];
3478c2ecf20Sopenharmony_ci	adev->acp.acp_cell[3].pdata_size = sizeof(struct i2s_platform_data);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	r = mfd_add_hotplug_devices(adev->acp.parent, adev->acp.acp_cell,
3508c2ecf20Sopenharmony_ci								ACP_DEVS);
3518c2ecf20Sopenharmony_ci	if (r)
3528c2ecf20Sopenharmony_ci		goto failure;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	r = device_for_each_child(adev->acp.parent, &adev->acp.acp_genpd->gpd,
3558c2ecf20Sopenharmony_ci				  acp_genpd_add_device);
3568c2ecf20Sopenharmony_ci	if (r)
3578c2ecf20Sopenharmony_ci		goto failure;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	/* Assert Soft reset of ACP */
3608c2ecf20Sopenharmony_ci	val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	val |= ACP_SOFT_RESET__SoftResetAud_MASK;
3638c2ecf20Sopenharmony_ci	cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE;
3668c2ecf20Sopenharmony_ci	while (true) {
3678c2ecf20Sopenharmony_ci		val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
3688c2ecf20Sopenharmony_ci		if (ACP_SOFT_RESET__SoftResetAudDone_MASK ==
3698c2ecf20Sopenharmony_ci		    (val & ACP_SOFT_RESET__SoftResetAudDone_MASK))
3708c2ecf20Sopenharmony_ci			break;
3718c2ecf20Sopenharmony_ci		if (--count == 0) {
3728c2ecf20Sopenharmony_ci			dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
3738c2ecf20Sopenharmony_ci			r = -ETIMEDOUT;
3748c2ecf20Sopenharmony_ci			goto failure;
3758c2ecf20Sopenharmony_ci		}
3768c2ecf20Sopenharmony_ci		udelay(100);
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci	/* Enable clock to ACP and wait until the clock is enabled */
3798c2ecf20Sopenharmony_ci	val = cgs_read_register(adev->acp.cgs_device, mmACP_CONTROL);
3808c2ecf20Sopenharmony_ci	val = val | ACP_CONTROL__ClkEn_MASK;
3818c2ecf20Sopenharmony_ci	cgs_write_register(adev->acp.cgs_device, mmACP_CONTROL, val);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	count = ACP_CLOCK_EN_TIME_OUT_VALUE;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	while (true) {
3868c2ecf20Sopenharmony_ci		val = cgs_read_register(adev->acp.cgs_device, mmACP_STATUS);
3878c2ecf20Sopenharmony_ci		if (val & (u32) 0x1)
3888c2ecf20Sopenharmony_ci			break;
3898c2ecf20Sopenharmony_ci		if (--count == 0) {
3908c2ecf20Sopenharmony_ci			dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
3918c2ecf20Sopenharmony_ci			r = -ETIMEDOUT;
3928c2ecf20Sopenharmony_ci			goto failure;
3938c2ecf20Sopenharmony_ci		}
3948c2ecf20Sopenharmony_ci		udelay(100);
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci	/* Deassert the SOFT RESET flags */
3978c2ecf20Sopenharmony_ci	val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
3988c2ecf20Sopenharmony_ci	val &= ~ACP_SOFT_RESET__SoftResetAud_MASK;
3998c2ecf20Sopenharmony_ci	cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val);
4008c2ecf20Sopenharmony_ci	return 0;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cifailure:
4038c2ecf20Sopenharmony_ci	kfree(i2s_pdata);
4048c2ecf20Sopenharmony_ci	kfree(adev->acp.acp_res);
4058c2ecf20Sopenharmony_ci	kfree(adev->acp.acp_cell);
4068c2ecf20Sopenharmony_ci	kfree(adev->acp.acp_genpd);
4078c2ecf20Sopenharmony_ci	return r;
4088c2ecf20Sopenharmony_ci}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci/**
4118c2ecf20Sopenharmony_ci * acp_hw_fini - stop the hardware block
4128c2ecf20Sopenharmony_ci *
4138c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer
4148c2ecf20Sopenharmony_ci *
4158c2ecf20Sopenharmony_ci */
4168c2ecf20Sopenharmony_cistatic int acp_hw_fini(void *handle)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	u32 val = 0;
4198c2ecf20Sopenharmony_ci	u32 count = 0;
4208c2ecf20Sopenharmony_ci	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	/* return early if no ACP */
4238c2ecf20Sopenharmony_ci	if (!adev->acp.acp_genpd) {
4248c2ecf20Sopenharmony_ci		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
4258c2ecf20Sopenharmony_ci		return 0;
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	/* Assert Soft reset of ACP */
4298c2ecf20Sopenharmony_ci	val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	val |= ACP_SOFT_RESET__SoftResetAud_MASK;
4328c2ecf20Sopenharmony_ci	cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE;
4358c2ecf20Sopenharmony_ci	while (true) {
4368c2ecf20Sopenharmony_ci		val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
4378c2ecf20Sopenharmony_ci		if (ACP_SOFT_RESET__SoftResetAudDone_MASK ==
4388c2ecf20Sopenharmony_ci		    (val & ACP_SOFT_RESET__SoftResetAudDone_MASK))
4398c2ecf20Sopenharmony_ci			break;
4408c2ecf20Sopenharmony_ci		if (--count == 0) {
4418c2ecf20Sopenharmony_ci			dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
4428c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
4438c2ecf20Sopenharmony_ci		}
4448c2ecf20Sopenharmony_ci		udelay(100);
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci	/* Disable ACP clock */
4478c2ecf20Sopenharmony_ci	val = cgs_read_register(adev->acp.cgs_device, mmACP_CONTROL);
4488c2ecf20Sopenharmony_ci	val &= ~ACP_CONTROL__ClkEn_MASK;
4498c2ecf20Sopenharmony_ci	cgs_write_register(adev->acp.cgs_device, mmACP_CONTROL, val);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	count = ACP_CLOCK_EN_TIME_OUT_VALUE;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	while (true) {
4548c2ecf20Sopenharmony_ci		val = cgs_read_register(adev->acp.cgs_device, mmACP_STATUS);
4558c2ecf20Sopenharmony_ci		if (val & (u32) 0x1)
4568c2ecf20Sopenharmony_ci			break;
4578c2ecf20Sopenharmony_ci		if (--count == 0) {
4588c2ecf20Sopenharmony_ci			dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
4598c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
4608c2ecf20Sopenharmony_ci		}
4618c2ecf20Sopenharmony_ci		udelay(100);
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	device_for_each_child(adev->acp.parent, NULL,
4658c2ecf20Sopenharmony_ci			      acp_genpd_remove_device);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	mfd_remove_devices(adev->acp.parent);
4688c2ecf20Sopenharmony_ci	kfree(adev->acp.acp_res);
4698c2ecf20Sopenharmony_ci	kfree(adev->acp.acp_genpd);
4708c2ecf20Sopenharmony_ci	kfree(adev->acp.acp_cell);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	return 0;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic int acp_suspend(void *handle)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	/* power up on suspend */
4808c2ecf20Sopenharmony_ci	if (!adev->acp.acp_cell)
4818c2ecf20Sopenharmony_ci		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
4828c2ecf20Sopenharmony_ci	return 0;
4838c2ecf20Sopenharmony_ci}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_cistatic int acp_resume(void *handle)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/* power down again on resume */
4908c2ecf20Sopenharmony_ci	if (!adev->acp.acp_cell)
4918c2ecf20Sopenharmony_ci		amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
4928c2ecf20Sopenharmony_ci	return 0;
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic int acp_early_init(void *handle)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	return 0;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistatic bool acp_is_idle(void *handle)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	return true;
5038c2ecf20Sopenharmony_ci}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_cistatic int acp_wait_for_idle(void *handle)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	return 0;
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic int acp_soft_reset(void *handle)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	return 0;
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_cistatic int acp_set_clockgating_state(void *handle,
5168c2ecf20Sopenharmony_ci				     enum amd_clockgating_state state)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	return 0;
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic int acp_set_powergating_state(void *handle,
5228c2ecf20Sopenharmony_ci				     enum amd_powergating_state state)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
5258c2ecf20Sopenharmony_ci	bool enable = (state == AMD_PG_STATE_GATE);
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, enable);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	return 0;
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cistatic const struct amd_ip_funcs acp_ip_funcs = {
5338c2ecf20Sopenharmony_ci	.name = "acp_ip",
5348c2ecf20Sopenharmony_ci	.early_init = acp_early_init,
5358c2ecf20Sopenharmony_ci	.late_init = NULL,
5368c2ecf20Sopenharmony_ci	.sw_init = acp_sw_init,
5378c2ecf20Sopenharmony_ci	.sw_fini = acp_sw_fini,
5388c2ecf20Sopenharmony_ci	.hw_init = acp_hw_init,
5398c2ecf20Sopenharmony_ci	.hw_fini = acp_hw_fini,
5408c2ecf20Sopenharmony_ci	.suspend = acp_suspend,
5418c2ecf20Sopenharmony_ci	.resume = acp_resume,
5428c2ecf20Sopenharmony_ci	.is_idle = acp_is_idle,
5438c2ecf20Sopenharmony_ci	.wait_for_idle = acp_wait_for_idle,
5448c2ecf20Sopenharmony_ci	.soft_reset = acp_soft_reset,
5458c2ecf20Sopenharmony_ci	.set_clockgating_state = acp_set_clockgating_state,
5468c2ecf20Sopenharmony_ci	.set_powergating_state = acp_set_powergating_state,
5478c2ecf20Sopenharmony_ci};
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ciconst struct amdgpu_ip_block_version acp_ip_block =
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	.type = AMD_IP_BLOCK_TYPE_ACP,
5528c2ecf20Sopenharmony_ci	.major = 2,
5538c2ecf20Sopenharmony_ci	.minor = 2,
5548c2ecf20Sopenharmony_ci	.rev = 0,
5558c2ecf20Sopenharmony_ci	.funcs = &acp_ip_funcs,
5568c2ecf20Sopenharmony_ci};
557