1 /* 2 * Copyright 2015 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 #include <linux/irqdomain.h> 27 #include <linux/platform_device.h> 28 #include <sound/designware_i2s.h> 29 #include <sound/pcm.h> 30 31 #include "amdgpu.h" 32 #include "atom.h" 33 #include "amdgpu_acp.h" 34 35 #include "acp_gfx_if.h" 36 37 #define ACP_TILE_ON_MASK 0x03 38 #define ACP_TILE_OFF_MASK 0x02 39 #define ACP_TILE_ON_RETAIN_REG_MASK 0x1f 40 #define ACP_TILE_OFF_RETAIN_REG_MASK 0x20 41 42 #define ACP_TILE_P1_MASK 0x3e 43 #define ACP_TILE_P2_MASK 0x3d 44 #define ACP_TILE_DSP0_MASK 0x3b 45 #define ACP_TILE_DSP1_MASK 0x37 46 47 #define ACP_TILE_DSP2_MASK 0x2f 48 49 #define ACP_DMA_REGS_END 0x146c0 50 #define ACP_I2S_PLAY_REGS_START 0x14840 51 #define ACP_I2S_PLAY_REGS_END 0x148b4 52 #define ACP_I2S_CAP_REGS_START 0x148b8 53 #define ACP_I2S_CAP_REGS_END 0x1496c 54 55 #define ACP_I2S_COMP1_CAP_REG_OFFSET 0xac 56 #define ACP_I2S_COMP2_CAP_REG_OFFSET 0xa8 57 #define ACP_I2S_COMP1_PLAY_REG_OFFSET 0x6c 58 #define ACP_I2S_COMP2_PLAY_REG_OFFSET 0x68 59 60 #define mmACP_PGFSM_RETAIN_REG 0x51c9 61 #define mmACP_PGFSM_CONFIG_REG 0x51ca 62 #define mmACP_PGFSM_READ_REG_0 0x51cc 63 64 #define mmACP_MEM_SHUT_DOWN_REQ_LO 0x51f8 65 #define mmACP_MEM_SHUT_DOWN_REQ_HI 0x51f9 66 #define mmACP_MEM_SHUT_DOWN_STS_LO 0x51fa 67 #define mmACP_MEM_SHUT_DOWN_STS_HI 0x51fb 68 69 #define ACP_TIMEOUT_LOOP 0x000000FF 70 #define ACP_DEVS 3 71 #define ACP_SRC_ID 162 72 73 enum { 74 ACP_TILE_P1 = 0, 75 ACP_TILE_P2, 76 ACP_TILE_DSP0, 77 ACP_TILE_DSP1, 78 ACP_TILE_DSP2, 79 }; 80 81 static int acp_sw_init(void *handle) 82 { 83 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 84 85 adev->acp.parent = adev->dev; 86 87 adev->acp.cgs_device = 88 amdgpu_cgs_create_device(adev); 89 if (!adev->acp.cgs_device) 90 return -EINVAL; 91 92 return 0; 93 } 94 95 static int acp_sw_fini(void *handle) 96 { 97 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 98 99 if (adev->acp.cgs_device) 100 amdgpu_cgs_destroy_device(adev->acp.cgs_device); 101 102 return 0; 103 } 104 105 /** 106 * acp_hw_init - start and test ACP block 107 * 108 * @adev: amdgpu_device pointer 109 * 110 */ 111 static int acp_hw_init(void *handle) 112 { 113 int r; 114 uint64_t acp_base; 115 struct i2s_platform_data *i2s_pdata; 116 117 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 118 119 const struct amdgpu_ip_block_version *ip_version = 120 amdgpu_get_ip_block(adev, AMD_IP_BLOCK_TYPE_ACP); 121 122 if (!ip_version) 123 return -EINVAL; 124 125 r = amd_acp_hw_init(adev->acp.cgs_device, 126 ip_version->major, ip_version->minor); 127 /* -ENODEV means board uses AZ rather than ACP */ 128 if (r == -ENODEV) 129 return 0; 130 else if (r) 131 return r; 132 133 r = cgs_get_pci_resource(adev->acp.cgs_device, CGS_RESOURCE_TYPE_MMIO, 134 0x5289, 0, &acp_base); 135 if (r == -ENODEV) 136 return 0; 137 else if (r) 138 return r; 139 140 adev->acp.acp_cell = kzalloc(sizeof(struct mfd_cell) * ACP_DEVS, 141 GFP_KERNEL); 142 143 if (adev->acp.acp_cell == NULL) 144 return -ENOMEM; 145 146 adev->acp.acp_res = kzalloc(sizeof(struct resource) * 4, GFP_KERNEL); 147 148 if (adev->acp.acp_res == NULL) { 149 kfree(adev->acp.acp_cell); 150 return -ENOMEM; 151 } 152 153 i2s_pdata = kzalloc(sizeof(struct i2s_platform_data) * 2, GFP_KERNEL); 154 if (i2s_pdata == NULL) { 155 kfree(adev->acp.acp_res); 156 kfree(adev->acp.acp_cell); 157 return -ENOMEM; 158 } 159 160 i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET; 161 i2s_pdata[0].cap = DWC_I2S_PLAY; 162 i2s_pdata[0].snd_rates = SNDRV_PCM_RATE_8000_96000; 163 i2s_pdata[0].i2s_reg_comp1 = ACP_I2S_COMP1_PLAY_REG_OFFSET; 164 i2s_pdata[0].i2s_reg_comp2 = ACP_I2S_COMP2_PLAY_REG_OFFSET; 165 166 i2s_pdata[1].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET | 167 DW_I2S_QUIRK_COMP_PARAM1; 168 i2s_pdata[1].cap = DWC_I2S_RECORD; 169 i2s_pdata[1].snd_rates = SNDRV_PCM_RATE_8000_96000; 170 i2s_pdata[1].i2s_reg_comp1 = ACP_I2S_COMP1_CAP_REG_OFFSET; 171 i2s_pdata[1].i2s_reg_comp2 = ACP_I2S_COMP2_CAP_REG_OFFSET; 172 173 adev->acp.acp_res[0].name = "acp2x_dma"; 174 adev->acp.acp_res[0].flags = IORESOURCE_MEM; 175 adev->acp.acp_res[0].start = acp_base; 176 adev->acp.acp_res[0].end = acp_base + ACP_DMA_REGS_END; 177 178 adev->acp.acp_res[1].name = "acp2x_dw_i2s_play"; 179 adev->acp.acp_res[1].flags = IORESOURCE_MEM; 180 adev->acp.acp_res[1].start = acp_base + ACP_I2S_PLAY_REGS_START; 181 adev->acp.acp_res[1].end = acp_base + ACP_I2S_PLAY_REGS_END; 182 183 adev->acp.acp_res[2].name = "acp2x_dw_i2s_cap"; 184 adev->acp.acp_res[2].flags = IORESOURCE_MEM; 185 adev->acp.acp_res[2].start = acp_base + ACP_I2S_CAP_REGS_START; 186 adev->acp.acp_res[2].end = acp_base + ACP_I2S_CAP_REGS_END; 187 188 adev->acp.acp_res[3].name = "acp2x_dma_irq"; 189 adev->acp.acp_res[3].flags = IORESOURCE_IRQ; 190 adev->acp.acp_res[3].start = amdgpu_irq_create_mapping(adev, 162); 191 adev->acp.acp_res[3].end = adev->acp.acp_res[3].start; 192 193 adev->acp.acp_cell[0].name = "acp_audio_dma"; 194 adev->acp.acp_cell[0].num_resources = 4; 195 adev->acp.acp_cell[0].resources = &adev->acp.acp_res[0]; 196 197 adev->acp.acp_cell[1].name = "designware-i2s"; 198 adev->acp.acp_cell[1].num_resources = 1; 199 adev->acp.acp_cell[1].resources = &adev->acp.acp_res[1]; 200 adev->acp.acp_cell[1].platform_data = &i2s_pdata[0]; 201 adev->acp.acp_cell[1].pdata_size = sizeof(struct i2s_platform_data); 202 203 adev->acp.acp_cell[2].name = "designware-i2s"; 204 adev->acp.acp_cell[2].num_resources = 1; 205 adev->acp.acp_cell[2].resources = &adev->acp.acp_res[2]; 206 adev->acp.acp_cell[2].platform_data = &i2s_pdata[1]; 207 adev->acp.acp_cell[2].pdata_size = sizeof(struct i2s_platform_data); 208 209 r = mfd_add_hotplug_devices(adev->acp.parent, adev->acp.acp_cell, 210 ACP_DEVS); 211 if (r) 212 return r; 213 214 return 0; 215 } 216 217 /** 218 * acp_hw_fini - stop the hardware block 219 * 220 * @adev: amdgpu_device pointer 221 * 222 */ 223 static int acp_hw_fini(void *handle) 224 { 225 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 226 227 mfd_remove_devices(adev->acp.parent); 228 kfree(adev->acp.acp_res); 229 kfree(adev->acp.acp_cell); 230 231 return 0; 232 } 233 234 static int acp_suspend(void *handle) 235 { 236 return 0; 237 } 238 239 static int acp_resume(void *handle) 240 { 241 return 0; 242 } 243 244 static int acp_early_init(void *handle) 245 { 246 return 0; 247 } 248 249 static bool acp_is_idle(void *handle) 250 { 251 return true; 252 } 253 254 static int acp_wait_for_idle(void *handle) 255 { 256 return 0; 257 } 258 259 static int acp_soft_reset(void *handle) 260 { 261 return 0; 262 } 263 264 static void acp_print_status(void *handle) 265 { 266 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 267 268 dev_info(adev->dev, "ACP STATUS\n"); 269 } 270 271 static int acp_set_clockgating_state(void *handle, 272 enum amd_clockgating_state state) 273 { 274 return 0; 275 } 276 277 static int acp_set_powergating_state(void *handle, 278 enum amd_powergating_state state) 279 { 280 return 0; 281 } 282 283 const struct amd_ip_funcs acp_ip_funcs = { 284 .early_init = acp_early_init, 285 .late_init = NULL, 286 .sw_init = acp_sw_init, 287 .sw_fini = acp_sw_fini, 288 .hw_init = acp_hw_init, 289 .hw_fini = acp_hw_fini, 290 .suspend = acp_suspend, 291 .resume = acp_resume, 292 .is_idle = acp_is_idle, 293 .wait_for_idle = acp_wait_for_idle, 294 .soft_reset = acp_soft_reset, 295 .print_status = acp_print_status, 296 .set_clockgating_state = acp_set_clockgating_state, 297 .set_powergating_state = acp_set_powergating_state, 298 }; 299