Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2015 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 
0026 #include <linux/irqdomain.h>
0027 #include <linux/pci.h>
0028 #include <linux/pm_domain.h>
0029 #include <linux/platform_device.h>
0030 #include <sound/designware_i2s.h>
0031 #include <sound/pcm.h>
0032 #include <linux/acpi.h>
0033 #include <linux/dmi.h>
0034 
0035 #include "amdgpu.h"
0036 #include "atom.h"
0037 #include "amdgpu_acp.h"
0038 
0039 #include "acp_gfx_if.h"
0040 
0041 #define ST_JADEITE 1
0042 #define ACP_TILE_ON_MASK            0x03
0043 #define ACP_TILE_OFF_MASK           0x02
0044 #define ACP_TILE_ON_RETAIN_REG_MASK     0x1f
0045 #define ACP_TILE_OFF_RETAIN_REG_MASK        0x20
0046 
0047 #define ACP_TILE_P1_MASK            0x3e
0048 #define ACP_TILE_P2_MASK            0x3d
0049 #define ACP_TILE_DSP0_MASK          0x3b
0050 #define ACP_TILE_DSP1_MASK          0x37
0051 
0052 #define ACP_TILE_DSP2_MASK          0x2f
0053 
0054 #define ACP_DMA_REGS_END            0x146c0
0055 #define ACP_I2S_PLAY_REGS_START         0x14840
0056 #define ACP_I2S_PLAY_REGS_END           0x148b4
0057 #define ACP_I2S_CAP_REGS_START          0x148b8
0058 #define ACP_I2S_CAP_REGS_END            0x1496c
0059 
0060 #define ACP_I2S_COMP1_CAP_REG_OFFSET        0xac
0061 #define ACP_I2S_COMP2_CAP_REG_OFFSET        0xa8
0062 #define ACP_I2S_COMP1_PLAY_REG_OFFSET       0x6c
0063 #define ACP_I2S_COMP2_PLAY_REG_OFFSET       0x68
0064 #define ACP_BT_PLAY_REGS_START          0x14970
0065 #define ACP_BT_PLAY_REGS_END            0x14a24
0066 #define ACP_BT_COMP1_REG_OFFSET         0xac
0067 #define ACP_BT_COMP2_REG_OFFSET         0xa8
0068 
0069 #define mmACP_PGFSM_RETAIN_REG          0x51c9
0070 #define mmACP_PGFSM_CONFIG_REG          0x51ca
0071 #define mmACP_PGFSM_READ_REG_0          0x51cc
0072 
0073 #define mmACP_MEM_SHUT_DOWN_REQ_LO      0x51f8
0074 #define mmACP_MEM_SHUT_DOWN_REQ_HI      0x51f9
0075 #define mmACP_MEM_SHUT_DOWN_STS_LO      0x51fa
0076 #define mmACP_MEM_SHUT_DOWN_STS_HI      0x51fb
0077 
0078 #define mmACP_CONTROL               0x5131
0079 #define mmACP_STATUS                0x5133
0080 #define mmACP_SOFT_RESET            0x5134
0081 #define ACP_CONTROL__ClkEn_MASK         0x1
0082 #define ACP_SOFT_RESET__SoftResetAud_MASK   0x100
0083 #define ACP_SOFT_RESET__SoftResetAudDone_MASK   0x1000000
0084 #define ACP_CLOCK_EN_TIME_OUT_VALUE     0x000000FF
0085 #define ACP_SOFT_RESET_DONE_TIME_OUT_VALUE  0x000000FF
0086 
0087 #define ACP_TIMEOUT_LOOP            0x000000FF
0088 #define ACP_DEVS                4
0089 #define ACP_SRC_ID              162
0090 
0091 static unsigned long acp_machine_id;
0092 
0093 enum {
0094     ACP_TILE_P1 = 0,
0095     ACP_TILE_P2,
0096     ACP_TILE_DSP0,
0097     ACP_TILE_DSP1,
0098     ACP_TILE_DSP2,
0099 };
0100 
0101 static int acp_sw_init(void *handle)
0102 {
0103     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0104 
0105     adev->acp.parent = adev->dev;
0106 
0107     adev->acp.cgs_device =
0108         amdgpu_cgs_create_device(adev);
0109     if (!adev->acp.cgs_device)
0110         return -EINVAL;
0111 
0112     return 0;
0113 }
0114 
0115 static int acp_sw_fini(void *handle)
0116 {
0117     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0118 
0119     if (adev->acp.cgs_device)
0120         amdgpu_cgs_destroy_device(adev->acp.cgs_device);
0121 
0122     return 0;
0123 }
0124 
0125 struct acp_pm_domain {
0126     void *adev;
0127     struct generic_pm_domain gpd;
0128 };
0129 
0130 static int acp_poweroff(struct generic_pm_domain *genpd)
0131 {
0132     struct acp_pm_domain *apd;
0133     struct amdgpu_device *adev;
0134 
0135     apd = container_of(genpd, struct acp_pm_domain, gpd);
0136     adev = apd->adev;
0137     /* call smu to POWER GATE ACP block
0138      * smu will
0139      * 1. turn off the acp clock
0140      * 2. power off the acp tiles
0141      * 3. check and enter ulv state
0142      */
0143     amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
0144     return 0;
0145 }
0146 
0147 static int acp_poweron(struct generic_pm_domain *genpd)
0148 {
0149     struct acp_pm_domain *apd;
0150     struct amdgpu_device *adev;
0151 
0152     apd = container_of(genpd, struct acp_pm_domain, gpd);
0153     adev = apd->adev;
0154     /* call smu to UNGATE ACP block
0155      * smu will
0156      * 1. exit ulv
0157      * 2. turn on acp clock
0158      * 3. power on acp tiles
0159      */
0160     amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
0161     return 0;
0162 }
0163 
0164 static int acp_genpd_add_device(struct device *dev, void *data)
0165 {
0166     struct generic_pm_domain *gpd = data;
0167     int ret;
0168 
0169     ret = pm_genpd_add_device(gpd, dev);
0170     if (ret)
0171         dev_err(dev, "Failed to add dev to genpd %d\n", ret);
0172 
0173     return ret;
0174 }
0175 
0176 static int acp_genpd_remove_device(struct device *dev, void *data)
0177 {
0178     int ret;
0179 
0180     ret = pm_genpd_remove_device(dev);
0181     if (ret)
0182         dev_err(dev, "Failed to remove dev from genpd %d\n", ret);
0183 
0184     /* Continue to remove */
0185     return 0;
0186 }
0187 
0188 static int acp_quirk_cb(const struct dmi_system_id *id)
0189 {
0190     acp_machine_id = ST_JADEITE;
0191     return 1;
0192 }
0193 
0194 static const struct dmi_system_id acp_quirk_table[] = {
0195     {
0196         .callback = acp_quirk_cb,
0197         .matches = {
0198             DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMD"),
0199             DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jadeite"),
0200         }
0201     },
0202     {
0203         .callback = acp_quirk_cb,
0204         .matches = {
0205             DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "IP3 Technology CO.,Ltd."),
0206             DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ASN1D"),
0207         },
0208     },
0209     {
0210         .callback = acp_quirk_cb,
0211         .matches = {
0212             DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Standard"),
0213             DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ASN10"),
0214         },
0215     },
0216     {}
0217 };
0218 
0219 /**
0220  * acp_hw_init - start and test ACP block
0221  *
0222  * @handle: handle used to pass amdgpu_device pointer
0223  *
0224  */
0225 static int acp_hw_init(void *handle)
0226 {
0227     int r;
0228     u64 acp_base;
0229     u32 val = 0;
0230     u32 count = 0;
0231     struct i2s_platform_data *i2s_pdata = NULL;
0232 
0233     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0234 
0235     const struct amdgpu_ip_block *ip_block =
0236         amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_ACP);
0237 
0238     if (!ip_block)
0239         return -EINVAL;
0240 
0241     r = amd_acp_hw_init(adev->acp.cgs_device,
0242                 ip_block->version->major, ip_block->version->minor);
0243     /* -ENODEV means board uses AZ rather than ACP */
0244     if (r == -ENODEV) {
0245         amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
0246         return 0;
0247     } else if (r) {
0248         return r;
0249     }
0250 
0251     if (adev->rmmio_size == 0 || adev->rmmio_size < 0x5289)
0252         return -EINVAL;
0253 
0254     acp_base = adev->rmmio_base;
0255     adev->acp.acp_genpd = kzalloc(sizeof(struct acp_pm_domain), GFP_KERNEL);
0256     if (!adev->acp.acp_genpd)
0257         return -ENOMEM;
0258 
0259     adev->acp.acp_genpd->gpd.name = "ACP_AUDIO";
0260     adev->acp.acp_genpd->gpd.power_off = acp_poweroff;
0261     adev->acp.acp_genpd->gpd.power_on = acp_poweron;
0262     adev->acp.acp_genpd->adev = adev;
0263 
0264     pm_genpd_init(&adev->acp.acp_genpd->gpd, NULL, false);
0265     dmi_check_system(acp_quirk_table);
0266     switch (acp_machine_id) {
0267     case ST_JADEITE:
0268     {
0269         adev->acp.acp_cell = kcalloc(2, sizeof(struct mfd_cell),
0270                          GFP_KERNEL);
0271         if (!adev->acp.acp_cell) {
0272             r = -ENOMEM;
0273             goto failure;
0274         }
0275 
0276         adev->acp.acp_res = kcalloc(3, sizeof(struct resource), GFP_KERNEL);
0277         if (!adev->acp.acp_res) {
0278             r = -ENOMEM;
0279             goto failure;
0280         }
0281 
0282         i2s_pdata = kcalloc(1, sizeof(struct i2s_platform_data), GFP_KERNEL);
0283         if (!i2s_pdata) {
0284             r = -ENOMEM;
0285             goto failure;
0286         }
0287 
0288         i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
0289                       DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
0290         i2s_pdata[0].cap = DWC_I2S_PLAY | DWC_I2S_RECORD;
0291         i2s_pdata[0].snd_rates = SNDRV_PCM_RATE_8000_96000;
0292         i2s_pdata[0].i2s_reg_comp1 = ACP_I2S_COMP1_CAP_REG_OFFSET;
0293         i2s_pdata[0].i2s_reg_comp2 = ACP_I2S_COMP2_CAP_REG_OFFSET;
0294 
0295         adev->acp.acp_res[0].name = "acp2x_dma";
0296         adev->acp.acp_res[0].flags = IORESOURCE_MEM;
0297         adev->acp.acp_res[0].start = acp_base;
0298         adev->acp.acp_res[0].end = acp_base + ACP_DMA_REGS_END;
0299 
0300         adev->acp.acp_res[1].name = "acp2x_dw_i2s_play_cap";
0301         adev->acp.acp_res[1].flags = IORESOURCE_MEM;
0302         adev->acp.acp_res[1].start = acp_base + ACP_I2S_CAP_REGS_START;
0303         adev->acp.acp_res[1].end = acp_base + ACP_I2S_CAP_REGS_END;
0304 
0305         adev->acp.acp_res[2].name = "acp2x_dma_irq";
0306         adev->acp.acp_res[2].flags = IORESOURCE_IRQ;
0307         adev->acp.acp_res[2].start = amdgpu_irq_create_mapping(adev, 162);
0308         adev->acp.acp_res[2].end = adev->acp.acp_res[2].start;
0309 
0310         adev->acp.acp_cell[0].name = "acp_audio_dma";
0311         adev->acp.acp_cell[0].num_resources = 3;
0312         adev->acp.acp_cell[0].resources = &adev->acp.acp_res[0];
0313         adev->acp.acp_cell[0].platform_data = &adev->asic_type;
0314         adev->acp.acp_cell[0].pdata_size = sizeof(adev->asic_type);
0315 
0316         adev->acp.acp_cell[1].name = "designware-i2s";
0317         adev->acp.acp_cell[1].num_resources = 1;
0318         adev->acp.acp_cell[1].resources = &adev->acp.acp_res[1];
0319         adev->acp.acp_cell[1].platform_data = &i2s_pdata[0];
0320         adev->acp.acp_cell[1].pdata_size = sizeof(struct i2s_platform_data);
0321         r = mfd_add_hotplug_devices(adev->acp.parent, adev->acp.acp_cell, 2);
0322         if (r)
0323             goto failure;
0324         r = device_for_each_child(adev->acp.parent, &adev->acp.acp_genpd->gpd,
0325                       acp_genpd_add_device);
0326         if (r)
0327             goto failure;
0328         break;
0329     }
0330     default:
0331         adev->acp.acp_cell = kcalloc(ACP_DEVS, sizeof(struct mfd_cell),
0332                          GFP_KERNEL);
0333 
0334         if (!adev->acp.acp_cell) {
0335             r = -ENOMEM;
0336             goto failure;
0337         }
0338 
0339         adev->acp.acp_res = kcalloc(5, sizeof(struct resource), GFP_KERNEL);
0340         if (!adev->acp.acp_res) {
0341             r = -ENOMEM;
0342             goto failure;
0343         }
0344 
0345         i2s_pdata = kcalloc(3, sizeof(struct i2s_platform_data), GFP_KERNEL);
0346         if (!i2s_pdata) {
0347             r = -ENOMEM;
0348             goto failure;
0349         }
0350 
0351         switch (adev->asic_type) {
0352         case CHIP_STONEY:
0353             i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
0354                 DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
0355             break;
0356         default:
0357             i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET;
0358         }
0359         i2s_pdata[0].cap = DWC_I2S_PLAY;
0360         i2s_pdata[0].snd_rates = SNDRV_PCM_RATE_8000_96000;
0361         i2s_pdata[0].i2s_reg_comp1 = ACP_I2S_COMP1_PLAY_REG_OFFSET;
0362         i2s_pdata[0].i2s_reg_comp2 = ACP_I2S_COMP2_PLAY_REG_OFFSET;
0363         switch (adev->asic_type) {
0364         case CHIP_STONEY:
0365             i2s_pdata[1].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
0366                 DW_I2S_QUIRK_COMP_PARAM1 |
0367                 DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
0368             break;
0369         default:
0370             i2s_pdata[1].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
0371                 DW_I2S_QUIRK_COMP_PARAM1;
0372         }
0373 
0374         i2s_pdata[1].cap = DWC_I2S_RECORD;
0375         i2s_pdata[1].snd_rates = SNDRV_PCM_RATE_8000_96000;
0376         i2s_pdata[1].i2s_reg_comp1 = ACP_I2S_COMP1_CAP_REG_OFFSET;
0377         i2s_pdata[1].i2s_reg_comp2 = ACP_I2S_COMP2_CAP_REG_OFFSET;
0378 
0379         i2s_pdata[2].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET;
0380         switch (adev->asic_type) {
0381         case CHIP_STONEY:
0382             i2s_pdata[2].quirks |= DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
0383             break;
0384         default:
0385             break;
0386         }
0387 
0388         i2s_pdata[2].cap = DWC_I2S_PLAY | DWC_I2S_RECORD;
0389         i2s_pdata[2].snd_rates = SNDRV_PCM_RATE_8000_96000;
0390         i2s_pdata[2].i2s_reg_comp1 = ACP_BT_COMP1_REG_OFFSET;
0391         i2s_pdata[2].i2s_reg_comp2 = ACP_BT_COMP2_REG_OFFSET;
0392 
0393         adev->acp.acp_res[0].name = "acp2x_dma";
0394         adev->acp.acp_res[0].flags = IORESOURCE_MEM;
0395         adev->acp.acp_res[0].start = acp_base;
0396         adev->acp.acp_res[0].end = acp_base + ACP_DMA_REGS_END;
0397 
0398         adev->acp.acp_res[1].name = "acp2x_dw_i2s_play";
0399         adev->acp.acp_res[1].flags = IORESOURCE_MEM;
0400         adev->acp.acp_res[1].start = acp_base + ACP_I2S_PLAY_REGS_START;
0401         adev->acp.acp_res[1].end = acp_base + ACP_I2S_PLAY_REGS_END;
0402 
0403         adev->acp.acp_res[2].name = "acp2x_dw_i2s_cap";
0404         adev->acp.acp_res[2].flags = IORESOURCE_MEM;
0405         adev->acp.acp_res[2].start = acp_base + ACP_I2S_CAP_REGS_START;
0406         adev->acp.acp_res[2].end = acp_base + ACP_I2S_CAP_REGS_END;
0407 
0408         adev->acp.acp_res[3].name = "acp2x_dw_bt_i2s_play_cap";
0409         adev->acp.acp_res[3].flags = IORESOURCE_MEM;
0410         adev->acp.acp_res[3].start = acp_base + ACP_BT_PLAY_REGS_START;
0411         adev->acp.acp_res[3].end = acp_base + ACP_BT_PLAY_REGS_END;
0412 
0413         adev->acp.acp_res[4].name = "acp2x_dma_irq";
0414         adev->acp.acp_res[4].flags = IORESOURCE_IRQ;
0415         adev->acp.acp_res[4].start = amdgpu_irq_create_mapping(adev, 162);
0416         adev->acp.acp_res[4].end = adev->acp.acp_res[4].start;
0417 
0418         adev->acp.acp_cell[0].name = "acp_audio_dma";
0419         adev->acp.acp_cell[0].num_resources = 5;
0420         adev->acp.acp_cell[0].resources = &adev->acp.acp_res[0];
0421         adev->acp.acp_cell[0].platform_data = &adev->asic_type;
0422         adev->acp.acp_cell[0].pdata_size = sizeof(adev->asic_type);
0423 
0424         adev->acp.acp_cell[1].name = "designware-i2s";
0425         adev->acp.acp_cell[1].num_resources = 1;
0426         adev->acp.acp_cell[1].resources = &adev->acp.acp_res[1];
0427         adev->acp.acp_cell[1].platform_data = &i2s_pdata[0];
0428         adev->acp.acp_cell[1].pdata_size = sizeof(struct i2s_platform_data);
0429 
0430         adev->acp.acp_cell[2].name = "designware-i2s";
0431         adev->acp.acp_cell[2].num_resources = 1;
0432         adev->acp.acp_cell[2].resources = &adev->acp.acp_res[2];
0433         adev->acp.acp_cell[2].platform_data = &i2s_pdata[1];
0434         adev->acp.acp_cell[2].pdata_size = sizeof(struct i2s_platform_data);
0435 
0436         adev->acp.acp_cell[3].name = "designware-i2s";
0437         adev->acp.acp_cell[3].num_resources = 1;
0438         adev->acp.acp_cell[3].resources = &adev->acp.acp_res[3];
0439         adev->acp.acp_cell[3].platform_data = &i2s_pdata[2];
0440         adev->acp.acp_cell[3].pdata_size = sizeof(struct i2s_platform_data);
0441 
0442         r = mfd_add_hotplug_devices(adev->acp.parent, adev->acp.acp_cell, ACP_DEVS);
0443         if (r)
0444             goto failure;
0445 
0446         r = device_for_each_child(adev->acp.parent, &adev->acp.acp_genpd->gpd,
0447                       acp_genpd_add_device);
0448         if (r)
0449             goto failure;
0450     }
0451 
0452     /* Assert Soft reset of ACP */
0453     val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
0454 
0455     val |= ACP_SOFT_RESET__SoftResetAud_MASK;
0456     cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val);
0457 
0458     count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE;
0459     while (true) {
0460         val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
0461         if (ACP_SOFT_RESET__SoftResetAudDone_MASK ==
0462             (val & ACP_SOFT_RESET__SoftResetAudDone_MASK))
0463             break;
0464         if (--count == 0) {
0465             dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
0466             r = -ETIMEDOUT;
0467             goto failure;
0468         }
0469         udelay(100);
0470     }
0471     /* Enable clock to ACP and wait until the clock is enabled */
0472     val = cgs_read_register(adev->acp.cgs_device, mmACP_CONTROL);
0473     val = val | ACP_CONTROL__ClkEn_MASK;
0474     cgs_write_register(adev->acp.cgs_device, mmACP_CONTROL, val);
0475 
0476     count = ACP_CLOCK_EN_TIME_OUT_VALUE;
0477 
0478     while (true) {
0479         val = cgs_read_register(adev->acp.cgs_device, mmACP_STATUS);
0480         if (val & (u32) 0x1)
0481             break;
0482         if (--count == 0) {
0483             dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
0484             r = -ETIMEDOUT;
0485             goto failure;
0486         }
0487         udelay(100);
0488     }
0489     /* Deassert the SOFT RESET flags */
0490     val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
0491     val &= ~ACP_SOFT_RESET__SoftResetAud_MASK;
0492     cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val);
0493     return 0;
0494 
0495 failure:
0496     kfree(i2s_pdata);
0497     kfree(adev->acp.acp_res);
0498     kfree(adev->acp.acp_cell);
0499     kfree(adev->acp.acp_genpd);
0500     return r;
0501 }
0502 
0503 /**
0504  * acp_hw_fini - stop the hardware block
0505  *
0506  * @handle: handle used to pass amdgpu_device pointer
0507  *
0508  */
0509 static int acp_hw_fini(void *handle)
0510 {
0511     u32 val = 0;
0512     u32 count = 0;
0513     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0514 
0515     /* return early if no ACP */
0516     if (!adev->acp.acp_genpd) {
0517         amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
0518         return 0;
0519     }
0520 
0521     /* Assert Soft reset of ACP */
0522     val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
0523 
0524     val |= ACP_SOFT_RESET__SoftResetAud_MASK;
0525     cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val);
0526 
0527     count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE;
0528     while (true) {
0529         val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
0530         if (ACP_SOFT_RESET__SoftResetAudDone_MASK ==
0531             (val & ACP_SOFT_RESET__SoftResetAudDone_MASK))
0532             break;
0533         if (--count == 0) {
0534             dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
0535             return -ETIMEDOUT;
0536         }
0537         udelay(100);
0538     }
0539     /* Disable ACP clock */
0540     val = cgs_read_register(adev->acp.cgs_device, mmACP_CONTROL);
0541     val &= ~ACP_CONTROL__ClkEn_MASK;
0542     cgs_write_register(adev->acp.cgs_device, mmACP_CONTROL, val);
0543 
0544     count = ACP_CLOCK_EN_TIME_OUT_VALUE;
0545 
0546     while (true) {
0547         val = cgs_read_register(adev->acp.cgs_device, mmACP_STATUS);
0548         if (val & (u32) 0x1)
0549             break;
0550         if (--count == 0) {
0551             dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
0552             return -ETIMEDOUT;
0553         }
0554         udelay(100);
0555     }
0556 
0557     device_for_each_child(adev->acp.parent, NULL,
0558                   acp_genpd_remove_device);
0559 
0560     mfd_remove_devices(adev->acp.parent);
0561     kfree(adev->acp.acp_res);
0562     kfree(adev->acp.acp_genpd);
0563     kfree(adev->acp.acp_cell);
0564 
0565     return 0;
0566 }
0567 
0568 static int acp_suspend(void *handle)
0569 {
0570     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0571 
0572     /* power up on suspend */
0573     if (!adev->acp.acp_cell)
0574         amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
0575     return 0;
0576 }
0577 
0578 static int acp_resume(void *handle)
0579 {
0580     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0581 
0582     /* power down again on resume */
0583     if (!adev->acp.acp_cell)
0584         amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
0585     return 0;
0586 }
0587 
0588 static int acp_early_init(void *handle)
0589 {
0590     return 0;
0591 }
0592 
0593 static bool acp_is_idle(void *handle)
0594 {
0595     return true;
0596 }
0597 
0598 static int acp_wait_for_idle(void *handle)
0599 {
0600     return 0;
0601 }
0602 
0603 static int acp_soft_reset(void *handle)
0604 {
0605     return 0;
0606 }
0607 
0608 static int acp_set_clockgating_state(void *handle,
0609                      enum amd_clockgating_state state)
0610 {
0611     return 0;
0612 }
0613 
0614 static int acp_set_powergating_state(void *handle,
0615                      enum amd_powergating_state state)
0616 {
0617     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0618     bool enable = (state == AMD_PG_STATE_GATE);
0619 
0620     amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, enable);
0621 
0622     return 0;
0623 }
0624 
0625 static const struct amd_ip_funcs acp_ip_funcs = {
0626     .name = "acp_ip",
0627     .early_init = acp_early_init,
0628     .late_init = NULL,
0629     .sw_init = acp_sw_init,
0630     .sw_fini = acp_sw_fini,
0631     .hw_init = acp_hw_init,
0632     .hw_fini = acp_hw_fini,
0633     .suspend = acp_suspend,
0634     .resume = acp_resume,
0635     .is_idle = acp_is_idle,
0636     .wait_for_idle = acp_wait_for_idle,
0637     .soft_reset = acp_soft_reset,
0638     .set_clockgating_state = acp_set_clockgating_state,
0639     .set_powergating_state = acp_set_powergating_state,
0640 };
0641 
0642 const struct amdgpu_ip_block_version acp_ip_block = {
0643     .type = AMD_IP_BLOCK_TYPE_ACP,
0644     .major = 2,
0645     .minor = 2,
0646     .rev = 0,
0647     .funcs = &acp_ip_funcs,
0648 };