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