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/pm_domain.h> 28 #include <linux/platform_device.h> 29 #include <sound/designware_i2s.h> 30 #include <sound/pcm.h> 31 32 #include "amdgpu.h" 33 #include "atom.h" 34 #include "amdgpu_acp.h" 35 36 #include "acp_gfx_if.h" 37 38 #define ACP_TILE_ON_MASK 0x03 39 #define ACP_TILE_OFF_MASK 0x02 40 #define ACP_TILE_ON_RETAIN_REG_MASK 0x1f 41 #define ACP_TILE_OFF_RETAIN_REG_MASK 0x20 42 43 #define ACP_TILE_P1_MASK 0x3e 44 #define ACP_TILE_P2_MASK 0x3d 45 #define ACP_TILE_DSP0_MASK 0x3b 46 #define ACP_TILE_DSP1_MASK 0x37 47 48 #define ACP_TILE_DSP2_MASK 0x2f 49 50 #define ACP_DMA_REGS_END 0x146c0 51 #define ACP_I2S_PLAY_REGS_START 0x14840 52 #define ACP_I2S_PLAY_REGS_END 0x148b4 53 #define ACP_I2S_CAP_REGS_START 0x148b8 54 #define ACP_I2S_CAP_REGS_END 0x1496c 55 56 #define ACP_I2S_COMP1_CAP_REG_OFFSET 0xac 57 #define ACP_I2S_COMP2_CAP_REG_OFFSET 0xa8 58 #define ACP_I2S_COMP1_PLAY_REG_OFFSET 0x6c 59 #define ACP_I2S_COMP2_PLAY_REG_OFFSET 0x68 60 61 #define mmACP_PGFSM_RETAIN_REG 0x51c9 62 #define mmACP_PGFSM_CONFIG_REG 0x51ca 63 #define mmACP_PGFSM_READ_REG_0 0x51cc 64 65 #define mmACP_MEM_SHUT_DOWN_REQ_LO 0x51f8 66 #define mmACP_MEM_SHUT_DOWN_REQ_HI 0x51f9 67 #define mmACP_MEM_SHUT_DOWN_STS_LO 0x51fa 68 #define mmACP_MEM_SHUT_DOWN_STS_HI 0x51fb 69 70 #define ACP_TIMEOUT_LOOP 0x000000FF 71 #define ACP_DEVS 3 72 #define ACP_SRC_ID 162 73 74 enum { 75 ACP_TILE_P1 = 0, 76 ACP_TILE_P2, 77 ACP_TILE_DSP0, 78 ACP_TILE_DSP1, 79 ACP_TILE_DSP2, 80 }; 81 82 static int acp_sw_init(void *handle) 83 { 84 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 85 86 adev->acp.parent = adev->dev; 87 88 adev->acp.cgs_device = 89 amdgpu_cgs_create_device(adev); 90 if (!adev->acp.cgs_device) 91 return -EINVAL; 92 93 return 0; 94 } 95 96 static int acp_sw_fini(void *handle) 97 { 98 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 99 100 if (adev->acp.cgs_device) 101 amdgpu_cgs_destroy_device(adev->acp.cgs_device); 102 103 return 0; 104 } 105 106 /* power off a tile/block within ACP */ 107 static int acp_suspend_tile(void *cgs_dev, int tile) 108 { 109 u32 val = 0; 110 u32 count = 0; 111 112 if ((tile < ACP_TILE_P1) || (tile > ACP_TILE_DSP2)) { 113 pr_err("Invalid ACP tile : %d to suspend\n", tile); 114 return -1; 115 } 116 117 val = cgs_read_register(cgs_dev, mmACP_PGFSM_READ_REG_0 + tile); 118 val &= ACP_TILE_ON_MASK; 119 120 if (val == 0x0) { 121 val = cgs_read_register(cgs_dev, mmACP_PGFSM_RETAIN_REG); 122 val = val | (1 << tile); 123 cgs_write_register(cgs_dev, mmACP_PGFSM_RETAIN_REG, val); 124 cgs_write_register(cgs_dev, mmACP_PGFSM_CONFIG_REG, 125 0x500 + tile); 126 127 count = ACP_TIMEOUT_LOOP; 128 while (true) { 129 val = cgs_read_register(cgs_dev, mmACP_PGFSM_READ_REG_0 130 + tile); 131 val = val & ACP_TILE_ON_MASK; 132 if (val == ACP_TILE_OFF_MASK) 133 break; 134 if (--count == 0) { 135 pr_err("Timeout reading ACP PGFSM status\n"); 136 return -ETIMEDOUT; 137 } 138 udelay(100); 139 } 140 141 val = cgs_read_register(cgs_dev, mmACP_PGFSM_RETAIN_REG); 142 143 val |= ACP_TILE_OFF_RETAIN_REG_MASK; 144 cgs_write_register(cgs_dev, mmACP_PGFSM_RETAIN_REG, val); 145 } 146 return 0; 147 } 148 149 /* power on a tile/block within ACP */ 150 static int acp_resume_tile(void *cgs_dev, int tile) 151 { 152 u32 val = 0; 153 u32 count = 0; 154 155 if ((tile < ACP_TILE_P1) || (tile > ACP_TILE_DSP2)) { 156 pr_err("Invalid ACP tile to resume\n"); 157 return -1; 158 } 159 160 val = cgs_read_register(cgs_dev, mmACP_PGFSM_READ_REG_0 + tile); 161 val = val & ACP_TILE_ON_MASK; 162 163 if (val != 0x0) { 164 cgs_write_register(cgs_dev, mmACP_PGFSM_CONFIG_REG, 165 0x600 + tile); 166 count = ACP_TIMEOUT_LOOP; 167 while (true) { 168 val = cgs_read_register(cgs_dev, mmACP_PGFSM_READ_REG_0 169 + tile); 170 val = val & ACP_TILE_ON_MASK; 171 if (val == 0x0) 172 break; 173 if (--count == 0) { 174 pr_err("Timeout reading ACP PGFSM status\n"); 175 return -ETIMEDOUT; 176 } 177 udelay(100); 178 } 179 val = cgs_read_register(cgs_dev, mmACP_PGFSM_RETAIN_REG); 180 if (tile == ACP_TILE_P1) 181 val = val & (ACP_TILE_P1_MASK); 182 else if (tile == ACP_TILE_P2) 183 val = val & (ACP_TILE_P2_MASK); 184 185 cgs_write_register(cgs_dev, mmACP_PGFSM_RETAIN_REG, val); 186 } 187 return 0; 188 } 189 190 struct acp_pm_domain { 191 void *cgs_dev; 192 struct generic_pm_domain gpd; 193 }; 194 195 static int acp_poweroff(struct generic_pm_domain *genpd) 196 { 197 int i, ret; 198 struct acp_pm_domain *apd; 199 200 apd = container_of(genpd, struct acp_pm_domain, gpd); 201 if (apd != NULL) { 202 /* Donot return abruptly if any of power tile fails to suspend. 203 * Log it and continue powering off other tile 204 */ 205 for (i = 4; i >= 0 ; i--) { 206 ret = acp_suspend_tile(apd->cgs_dev, ACP_TILE_P1 + i); 207 if (ret) 208 pr_err("ACP tile %d tile suspend failed\n", i); 209 } 210 } 211 return 0; 212 } 213 214 static int acp_poweron(struct generic_pm_domain *genpd) 215 { 216 int i, ret; 217 struct acp_pm_domain *apd; 218 219 apd = container_of(genpd, struct acp_pm_domain, gpd); 220 if (apd != NULL) { 221 for (i = 0; i < 2; i++) { 222 ret = acp_resume_tile(apd->cgs_dev, ACP_TILE_P1 + i); 223 if (ret) { 224 pr_err("ACP tile %d resume failed\n", i); 225 break; 226 } 227 } 228 229 /* Disable DSPs which are not going to be used */ 230 for (i = 0; i < 3; i++) { 231 ret = acp_suspend_tile(apd->cgs_dev, ACP_TILE_DSP0 + i); 232 /* Continue suspending other DSP, even if one fails */ 233 if (ret) 234 pr_err("ACP DSP %d suspend failed\n", i); 235 } 236 } 237 return 0; 238 } 239 240 static struct device *get_mfd_cell_dev(const char *device_name, int r) 241 { 242 char auto_dev_name[25]; 243 char buf[8]; 244 struct device *dev; 245 246 sprintf(buf, ".%d.auto", r); 247 strcpy(auto_dev_name, device_name); 248 strcat(auto_dev_name, buf); 249 dev = bus_find_device_by_name(&platform_bus_type, NULL, auto_dev_name); 250 dev_info(dev, "device %s added to pm domain\n", auto_dev_name); 251 252 return dev; 253 } 254 255 /** 256 * acp_hw_init - start and test ACP block 257 * 258 * @adev: amdgpu_device pointer 259 * 260 */ 261 static int acp_hw_init(void *handle) 262 { 263 int r, i; 264 uint64_t acp_base; 265 struct device *dev; 266 struct i2s_platform_data *i2s_pdata; 267 268 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 269 270 const struct amdgpu_ip_block_version *ip_version = 271 amdgpu_get_ip_block(adev, AMD_IP_BLOCK_TYPE_ACP); 272 273 if (!ip_version) 274 return -EINVAL; 275 276 r = amd_acp_hw_init(adev->acp.cgs_device, 277 ip_version->major, ip_version->minor); 278 /* -ENODEV means board uses AZ rather than ACP */ 279 if (r == -ENODEV) 280 return 0; 281 else if (r) 282 return r; 283 284 r = cgs_get_pci_resource(adev->acp.cgs_device, CGS_RESOURCE_TYPE_MMIO, 285 0x5289, 0, &acp_base); 286 if (r == -ENODEV) 287 return 0; 288 else if (r) 289 return r; 290 291 adev->acp.acp_genpd = kzalloc(sizeof(struct acp_pm_domain), GFP_KERNEL); 292 if (adev->acp.acp_genpd == NULL) 293 return -ENOMEM; 294 295 adev->acp.acp_genpd->gpd.name = "ACP_AUDIO"; 296 adev->acp.acp_genpd->gpd.power_off = acp_poweroff; 297 adev->acp.acp_genpd->gpd.power_on = acp_poweron; 298 299 300 adev->acp.acp_genpd->cgs_dev = adev->acp.cgs_device; 301 302 pm_genpd_init(&adev->acp.acp_genpd->gpd, NULL, false); 303 304 adev->acp.acp_cell = kzalloc(sizeof(struct mfd_cell) * ACP_DEVS, 305 GFP_KERNEL); 306 307 if (adev->acp.acp_cell == NULL) 308 return -ENOMEM; 309 310 adev->acp.acp_res = kzalloc(sizeof(struct resource) * 4, GFP_KERNEL); 311 312 if (adev->acp.acp_res == NULL) { 313 kfree(adev->acp.acp_cell); 314 return -ENOMEM; 315 } 316 317 i2s_pdata = kzalloc(sizeof(struct i2s_platform_data) * 2, GFP_KERNEL); 318 if (i2s_pdata == NULL) { 319 kfree(adev->acp.acp_res); 320 kfree(adev->acp.acp_cell); 321 return -ENOMEM; 322 } 323 324 i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET; 325 i2s_pdata[0].cap = DWC_I2S_PLAY; 326 i2s_pdata[0].snd_rates = SNDRV_PCM_RATE_8000_96000; 327 i2s_pdata[0].i2s_reg_comp1 = ACP_I2S_COMP1_PLAY_REG_OFFSET; 328 i2s_pdata[0].i2s_reg_comp2 = ACP_I2S_COMP2_PLAY_REG_OFFSET; 329 330 i2s_pdata[1].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET | 331 DW_I2S_QUIRK_COMP_PARAM1; 332 i2s_pdata[1].cap = DWC_I2S_RECORD; 333 i2s_pdata[1].snd_rates = SNDRV_PCM_RATE_8000_96000; 334 i2s_pdata[1].i2s_reg_comp1 = ACP_I2S_COMP1_CAP_REG_OFFSET; 335 i2s_pdata[1].i2s_reg_comp2 = ACP_I2S_COMP2_CAP_REG_OFFSET; 336 337 adev->acp.acp_res[0].name = "acp2x_dma"; 338 adev->acp.acp_res[0].flags = IORESOURCE_MEM; 339 adev->acp.acp_res[0].start = acp_base; 340 adev->acp.acp_res[0].end = acp_base + ACP_DMA_REGS_END; 341 342 adev->acp.acp_res[1].name = "acp2x_dw_i2s_play"; 343 adev->acp.acp_res[1].flags = IORESOURCE_MEM; 344 adev->acp.acp_res[1].start = acp_base + ACP_I2S_PLAY_REGS_START; 345 adev->acp.acp_res[1].end = acp_base + ACP_I2S_PLAY_REGS_END; 346 347 adev->acp.acp_res[2].name = "acp2x_dw_i2s_cap"; 348 adev->acp.acp_res[2].flags = IORESOURCE_MEM; 349 adev->acp.acp_res[2].start = acp_base + ACP_I2S_CAP_REGS_START; 350 adev->acp.acp_res[2].end = acp_base + ACP_I2S_CAP_REGS_END; 351 352 adev->acp.acp_res[3].name = "acp2x_dma_irq"; 353 adev->acp.acp_res[3].flags = IORESOURCE_IRQ; 354 adev->acp.acp_res[3].start = amdgpu_irq_create_mapping(adev, 162); 355 adev->acp.acp_res[3].end = adev->acp.acp_res[3].start; 356 357 adev->acp.acp_cell[0].name = "acp_audio_dma"; 358 adev->acp.acp_cell[0].num_resources = 4; 359 adev->acp.acp_cell[0].resources = &adev->acp.acp_res[0]; 360 361 adev->acp.acp_cell[1].name = "designware-i2s"; 362 adev->acp.acp_cell[1].num_resources = 1; 363 adev->acp.acp_cell[1].resources = &adev->acp.acp_res[1]; 364 adev->acp.acp_cell[1].platform_data = &i2s_pdata[0]; 365 adev->acp.acp_cell[1].pdata_size = sizeof(struct i2s_platform_data); 366 367 adev->acp.acp_cell[2].name = "designware-i2s"; 368 adev->acp.acp_cell[2].num_resources = 1; 369 adev->acp.acp_cell[2].resources = &adev->acp.acp_res[2]; 370 adev->acp.acp_cell[2].platform_data = &i2s_pdata[1]; 371 adev->acp.acp_cell[2].pdata_size = sizeof(struct i2s_platform_data); 372 373 r = mfd_add_hotplug_devices(adev->acp.parent, adev->acp.acp_cell, 374 ACP_DEVS); 375 if (r) 376 return r; 377 378 for (i = 0; i < ACP_DEVS ; i++) { 379 dev = get_mfd_cell_dev(adev->acp.acp_cell[i].name, i); 380 r = pm_genpd_add_device(&adev->acp.acp_genpd->gpd, dev); 381 if (r) { 382 dev_err(dev, "Failed to add dev to genpd\n"); 383 return r; 384 } 385 } 386 387 return 0; 388 } 389 390 /** 391 * acp_hw_fini - stop the hardware block 392 * 393 * @adev: amdgpu_device pointer 394 * 395 */ 396 static int acp_hw_fini(void *handle) 397 { 398 int i, ret; 399 struct device *dev; 400 401 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 402 403 for (i = 0; i < ACP_DEVS ; i++) { 404 dev = get_mfd_cell_dev(adev->acp.acp_cell[i].name, i); 405 ret = pm_genpd_remove_device(&adev->acp.acp_genpd->gpd, dev); 406 /* If removal fails, dont giveup and try rest */ 407 if (ret) 408 dev_err(dev, "remove dev from genpd failed\n"); 409 } 410 411 mfd_remove_devices(adev->acp.parent); 412 kfree(adev->acp.acp_res); 413 kfree(adev->acp.acp_genpd); 414 kfree(adev->acp.acp_cell); 415 416 return 0; 417 } 418 419 static int acp_suspend(void *handle) 420 { 421 return 0; 422 } 423 424 static int acp_resume(void *handle) 425 { 426 int i, ret; 427 struct acp_pm_domain *apd; 428 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 429 430 /* SMU block will power on ACP irrespective of ACP runtime status. 431 * Power off explicitly based on genpd ACP runtime status so that ACP 432 * hw and ACP-genpd status are in sync. 433 * 'suspend_power_off' represents "Power status before system suspend" 434 */ 435 if (adev->acp.acp_genpd->gpd.suspend_power_off == true) { 436 apd = container_of(&adev->acp.acp_genpd->gpd, 437 struct acp_pm_domain, gpd); 438 439 for (i = 4; i >= 0 ; i--) { 440 ret = acp_suspend_tile(apd->cgs_dev, ACP_TILE_P1 + i); 441 if (ret) 442 pr_err("ACP tile %d tile suspend failed\n", i); 443 } 444 } 445 return 0; 446 } 447 448 static int acp_early_init(void *handle) 449 { 450 return 0; 451 } 452 453 static bool acp_is_idle(void *handle) 454 { 455 return true; 456 } 457 458 static int acp_wait_for_idle(void *handle) 459 { 460 return 0; 461 } 462 463 static int acp_soft_reset(void *handle) 464 { 465 return 0; 466 } 467 468 static void acp_print_status(void *handle) 469 { 470 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 471 472 dev_info(adev->dev, "ACP STATUS\n"); 473 } 474 475 static int acp_set_clockgating_state(void *handle, 476 enum amd_clockgating_state state) 477 { 478 return 0; 479 } 480 481 static int acp_set_powergating_state(void *handle, 482 enum amd_powergating_state state) 483 { 484 return 0; 485 } 486 487 const struct amd_ip_funcs acp_ip_funcs = { 488 .early_init = acp_early_init, 489 .late_init = NULL, 490 .sw_init = acp_sw_init, 491 .sw_fini = acp_sw_fini, 492 .hw_init = acp_hw_init, 493 .hw_fini = acp_hw_fini, 494 .suspend = acp_suspend, 495 .resume = acp_resume, 496 .is_idle = acp_is_idle, 497 .wait_for_idle = acp_wait_for_idle, 498 .soft_reset = acp_soft_reset, 499 .print_status = acp_print_status, 500 .set_clockgating_state = acp_set_clockgating_state, 501 .set_powergating_state = acp_set_powergating_state, 502 }; 503