1fb4d8502Sjsg /*
2fb4d8502Sjsg * Copyright 2015 Advanced Micro Devices, Inc.
3fb4d8502Sjsg *
4fb4d8502Sjsg * Permission is hereby granted, free of charge, to any person obtaining a
5fb4d8502Sjsg * copy of this software and associated documentation files (the "Software"),
6fb4d8502Sjsg * to deal in the Software without restriction, including without limitation
7fb4d8502Sjsg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8fb4d8502Sjsg * and/or sell copies of the Software, and to permit persons to whom the
9fb4d8502Sjsg * Software is furnished to do so, subject to the following conditions:
10fb4d8502Sjsg *
11fb4d8502Sjsg * The above copyright notice and this permission notice shall be included in
12fb4d8502Sjsg * all copies or substantial portions of the Software.
13fb4d8502Sjsg *
14fb4d8502Sjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15fb4d8502Sjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16fb4d8502Sjsg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17fb4d8502Sjsg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18fb4d8502Sjsg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19fb4d8502Sjsg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20fb4d8502Sjsg * OTHER DEALINGS IN THE SOFTWARE.
21fb4d8502Sjsg *
22fb4d8502Sjsg * Authors: AMD
23fb4d8502Sjsg *
24fb4d8502Sjsg */
25fb4d8502Sjsg
26fb4d8502Sjsg #include <linux/irqdomain.h>
27c349dbc7Sjsg #include <linux/pci.h>
28fb4d8502Sjsg #include <linux/pm_domain.h>
29fb4d8502Sjsg #include <linux/platform_device.h>
30fb4d8502Sjsg #include <sound/designware_i2s.h>
31fb4d8502Sjsg #include <sound/pcm.h>
32*1bb76ff1Sjsg #include <linux/acpi.h>
33*1bb76ff1Sjsg #include <linux/dmi.h>
34fb4d8502Sjsg
35fb4d8502Sjsg #include "amdgpu.h"
36fb4d8502Sjsg #include "atom.h"
37fb4d8502Sjsg #include "amdgpu_acp.h"
38fb4d8502Sjsg
39fb4d8502Sjsg #include "acp_gfx_if.h"
40fb4d8502Sjsg
41*1bb76ff1Sjsg #define ST_JADEITE 1
42fb4d8502Sjsg #define ACP_TILE_ON_MASK 0x03
43fb4d8502Sjsg #define ACP_TILE_OFF_MASK 0x02
44fb4d8502Sjsg #define ACP_TILE_ON_RETAIN_REG_MASK 0x1f
45fb4d8502Sjsg #define ACP_TILE_OFF_RETAIN_REG_MASK 0x20
46fb4d8502Sjsg
47fb4d8502Sjsg #define ACP_TILE_P1_MASK 0x3e
48fb4d8502Sjsg #define ACP_TILE_P2_MASK 0x3d
49fb4d8502Sjsg #define ACP_TILE_DSP0_MASK 0x3b
50fb4d8502Sjsg #define ACP_TILE_DSP1_MASK 0x37
51fb4d8502Sjsg
52fb4d8502Sjsg #define ACP_TILE_DSP2_MASK 0x2f
53fb4d8502Sjsg
54fb4d8502Sjsg #define ACP_DMA_REGS_END 0x146c0
55fb4d8502Sjsg #define ACP_I2S_PLAY_REGS_START 0x14840
56fb4d8502Sjsg #define ACP_I2S_PLAY_REGS_END 0x148b4
57fb4d8502Sjsg #define ACP_I2S_CAP_REGS_START 0x148b8
58fb4d8502Sjsg #define ACP_I2S_CAP_REGS_END 0x1496c
59fb4d8502Sjsg
60fb4d8502Sjsg #define ACP_I2S_COMP1_CAP_REG_OFFSET 0xac
61fb4d8502Sjsg #define ACP_I2S_COMP2_CAP_REG_OFFSET 0xa8
62fb4d8502Sjsg #define ACP_I2S_COMP1_PLAY_REG_OFFSET 0x6c
63fb4d8502Sjsg #define ACP_I2S_COMP2_PLAY_REG_OFFSET 0x68
64fb4d8502Sjsg #define ACP_BT_PLAY_REGS_START 0x14970
65fb4d8502Sjsg #define ACP_BT_PLAY_REGS_END 0x14a24
66fb4d8502Sjsg #define ACP_BT_COMP1_REG_OFFSET 0xac
67fb4d8502Sjsg #define ACP_BT_COMP2_REG_OFFSET 0xa8
68fb4d8502Sjsg
69fb4d8502Sjsg #define mmACP_PGFSM_RETAIN_REG 0x51c9
70fb4d8502Sjsg #define mmACP_PGFSM_CONFIG_REG 0x51ca
71fb4d8502Sjsg #define mmACP_PGFSM_READ_REG_0 0x51cc
72fb4d8502Sjsg
73fb4d8502Sjsg #define mmACP_MEM_SHUT_DOWN_REQ_LO 0x51f8
74fb4d8502Sjsg #define mmACP_MEM_SHUT_DOWN_REQ_HI 0x51f9
75fb4d8502Sjsg #define mmACP_MEM_SHUT_DOWN_STS_LO 0x51fa
76fb4d8502Sjsg #define mmACP_MEM_SHUT_DOWN_STS_HI 0x51fb
77fb4d8502Sjsg
78fb4d8502Sjsg #define mmACP_CONTROL 0x5131
79fb4d8502Sjsg #define mmACP_STATUS 0x5133
80fb4d8502Sjsg #define mmACP_SOFT_RESET 0x5134
81fb4d8502Sjsg #define ACP_CONTROL__ClkEn_MASK 0x1
82fb4d8502Sjsg #define ACP_SOFT_RESET__SoftResetAud_MASK 0x100
83fb4d8502Sjsg #define ACP_SOFT_RESET__SoftResetAudDone_MASK 0x1000000
84fb4d8502Sjsg #define ACP_CLOCK_EN_TIME_OUT_VALUE 0x000000FF
85fb4d8502Sjsg #define ACP_SOFT_RESET_DONE_TIME_OUT_VALUE 0x000000FF
86fb4d8502Sjsg
87fb4d8502Sjsg #define ACP_TIMEOUT_LOOP 0x000000FF
88fb4d8502Sjsg #define ACP_DEVS 4
89fb4d8502Sjsg #define ACP_SRC_ID 162
90fb4d8502Sjsg
91*1bb76ff1Sjsg static unsigned long acp_machine_id;
92*1bb76ff1Sjsg
93fb4d8502Sjsg enum {
94fb4d8502Sjsg ACP_TILE_P1 = 0,
95fb4d8502Sjsg ACP_TILE_P2,
96fb4d8502Sjsg ACP_TILE_DSP0,
97fb4d8502Sjsg ACP_TILE_DSP1,
98fb4d8502Sjsg ACP_TILE_DSP2,
99fb4d8502Sjsg };
100fb4d8502Sjsg
acp_sw_init(void * handle)101fb4d8502Sjsg static int acp_sw_init(void *handle)
102fb4d8502Sjsg {
103fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
104fb4d8502Sjsg
105fb4d8502Sjsg adev->acp.parent = adev->dev;
106fb4d8502Sjsg
107fb4d8502Sjsg adev->acp.cgs_device =
108fb4d8502Sjsg amdgpu_cgs_create_device(adev);
109fb4d8502Sjsg if (!adev->acp.cgs_device)
110fb4d8502Sjsg return -EINVAL;
111fb4d8502Sjsg
112fb4d8502Sjsg return 0;
113fb4d8502Sjsg }
114fb4d8502Sjsg
acp_sw_fini(void * handle)115fb4d8502Sjsg static int acp_sw_fini(void *handle)
116fb4d8502Sjsg {
117fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
118fb4d8502Sjsg
119fb4d8502Sjsg if (adev->acp.cgs_device)
120fb4d8502Sjsg amdgpu_cgs_destroy_device(adev->acp.cgs_device);
121fb4d8502Sjsg
122fb4d8502Sjsg return 0;
123fb4d8502Sjsg }
124fb4d8502Sjsg
125fb4d8502Sjsg struct acp_pm_domain {
126c349dbc7Sjsg void *adev;
127fb4d8502Sjsg struct generic_pm_domain gpd;
128fb4d8502Sjsg };
129fb4d8502Sjsg
acp_poweroff(struct generic_pm_domain * genpd)130fb4d8502Sjsg static int acp_poweroff(struct generic_pm_domain *genpd)
131fb4d8502Sjsg {
132fb4d8502Sjsg struct acp_pm_domain *apd;
133c349dbc7Sjsg struct amdgpu_device *adev;
134fb4d8502Sjsg
135fb4d8502Sjsg apd = container_of(genpd, struct acp_pm_domain, gpd);
136c349dbc7Sjsg adev = apd->adev;
137c349dbc7Sjsg /* call smu to POWER GATE ACP block
138c349dbc7Sjsg * smu will
139c349dbc7Sjsg * 1. turn off the acp clock
140c349dbc7Sjsg * 2. power off the acp tiles
141c349dbc7Sjsg * 3. check and enter ulv state
142fb4d8502Sjsg */
143c349dbc7Sjsg amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
144fb4d8502Sjsg return 0;
145fb4d8502Sjsg }
146fb4d8502Sjsg
acp_poweron(struct generic_pm_domain * genpd)147fb4d8502Sjsg static int acp_poweron(struct generic_pm_domain *genpd)
148fb4d8502Sjsg {
149fb4d8502Sjsg struct acp_pm_domain *apd;
150c349dbc7Sjsg struct amdgpu_device *adev;
151fb4d8502Sjsg
152fb4d8502Sjsg apd = container_of(genpd, struct acp_pm_domain, gpd);
153c349dbc7Sjsg adev = apd->adev;
154c349dbc7Sjsg /* call smu to UNGATE ACP block
155c349dbc7Sjsg * smu will
156c349dbc7Sjsg * 1. exit ulv
157c349dbc7Sjsg * 2. turn on acp clock
158c349dbc7Sjsg * 3. power on acp tiles
159c349dbc7Sjsg */
160c349dbc7Sjsg amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
161fb4d8502Sjsg return 0;
162fb4d8502Sjsg }
163fb4d8502Sjsg
acp_genpd_add_device(struct device * dev,void * data)16408718c48Sjsg static int acp_genpd_add_device(struct device *dev, void *data)
165fb4d8502Sjsg {
16608718c48Sjsg struct generic_pm_domain *gpd = data;
16708718c48Sjsg int ret;
168fb4d8502Sjsg
16908718c48Sjsg ret = pm_genpd_add_device(gpd, dev);
17008718c48Sjsg if (ret)
17108718c48Sjsg dev_err(dev, "Failed to add dev to genpd %d\n", ret);
172fb4d8502Sjsg
17308718c48Sjsg return ret;
17408718c48Sjsg }
17508718c48Sjsg
acp_genpd_remove_device(struct device * dev,void * data)17608718c48Sjsg static int acp_genpd_remove_device(struct device *dev, void *data)
17708718c48Sjsg {
17808718c48Sjsg int ret;
17908718c48Sjsg
18008718c48Sjsg ret = pm_genpd_remove_device(dev);
18108718c48Sjsg if (ret)
18208718c48Sjsg dev_err(dev, "Failed to remove dev from genpd %d\n", ret);
18308718c48Sjsg
18408718c48Sjsg /* Continue to remove */
18508718c48Sjsg return 0;
186fb4d8502Sjsg }
187fb4d8502Sjsg
acp_quirk_cb(const struct dmi_system_id * id)188*1bb76ff1Sjsg static int acp_quirk_cb(const struct dmi_system_id *id)
189*1bb76ff1Sjsg {
190*1bb76ff1Sjsg acp_machine_id = ST_JADEITE;
191*1bb76ff1Sjsg return 1;
192*1bb76ff1Sjsg }
193*1bb76ff1Sjsg
194*1bb76ff1Sjsg static const struct dmi_system_id acp_quirk_table[] = {
195*1bb76ff1Sjsg {
196*1bb76ff1Sjsg .callback = acp_quirk_cb,
197*1bb76ff1Sjsg .matches = {
198*1bb76ff1Sjsg DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMD"),
199*1bb76ff1Sjsg DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jadeite"),
200*1bb76ff1Sjsg }
201*1bb76ff1Sjsg },
202*1bb76ff1Sjsg {
203*1bb76ff1Sjsg .callback = acp_quirk_cb,
204*1bb76ff1Sjsg .matches = {
205*1bb76ff1Sjsg DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "IP3 Technology CO.,Ltd."),
206*1bb76ff1Sjsg DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ASN1D"),
207*1bb76ff1Sjsg },
208*1bb76ff1Sjsg },
209*1bb76ff1Sjsg {
210*1bb76ff1Sjsg .callback = acp_quirk_cb,
211*1bb76ff1Sjsg .matches = {
212*1bb76ff1Sjsg DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Standard"),
213*1bb76ff1Sjsg DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ASN10"),
214*1bb76ff1Sjsg },
215*1bb76ff1Sjsg },
216*1bb76ff1Sjsg {}
217*1bb76ff1Sjsg };
218*1bb76ff1Sjsg
219fb4d8502Sjsg /**
220fb4d8502Sjsg * acp_hw_init - start and test ACP block
221fb4d8502Sjsg *
2225ca02815Sjsg * @handle: handle used to pass amdgpu_device pointer
223fb4d8502Sjsg *
224fb4d8502Sjsg */
acp_hw_init(void * handle)225fb4d8502Sjsg static int acp_hw_init(void *handle)
226fb4d8502Sjsg {
22708718c48Sjsg int r;
228*1bb76ff1Sjsg u64 acp_base;
229fb4d8502Sjsg u32 val = 0;
230fb4d8502Sjsg u32 count = 0;
231c349dbc7Sjsg struct i2s_platform_data *i2s_pdata = NULL;
232fb4d8502Sjsg
233fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
234fb4d8502Sjsg
235fb4d8502Sjsg const struct amdgpu_ip_block *ip_block =
236fb4d8502Sjsg amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_ACP);
237fb4d8502Sjsg
238fb4d8502Sjsg if (!ip_block)
239fb4d8502Sjsg return -EINVAL;
240fb4d8502Sjsg
241fb4d8502Sjsg r = amd_acp_hw_init(adev->acp.cgs_device,
242fb4d8502Sjsg ip_block->version->major, ip_block->version->minor);
243fb4d8502Sjsg /* -ENODEV means board uses AZ rather than ACP */
244c349dbc7Sjsg if (r == -ENODEV) {
245c349dbc7Sjsg amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
246fb4d8502Sjsg return 0;
247c349dbc7Sjsg } else if (r) {
248fb4d8502Sjsg return r;
249c349dbc7Sjsg }
250fb4d8502Sjsg
251fb4d8502Sjsg if (adev->rmmio_size == 0 || adev->rmmio_size < 0x5289)
252fb4d8502Sjsg return -EINVAL;
253fb4d8502Sjsg
254fb4d8502Sjsg acp_base = adev->rmmio_base;
255fb4d8502Sjsg adev->acp.acp_genpd = kzalloc(sizeof(struct acp_pm_domain), GFP_KERNEL);
256*1bb76ff1Sjsg if (!adev->acp.acp_genpd)
257fb4d8502Sjsg return -ENOMEM;
258fb4d8502Sjsg
259fb4d8502Sjsg adev->acp.acp_genpd->gpd.name = "ACP_AUDIO";
260fb4d8502Sjsg adev->acp.acp_genpd->gpd.power_off = acp_poweroff;
261fb4d8502Sjsg adev->acp.acp_genpd->gpd.power_on = acp_poweron;
262c349dbc7Sjsg adev->acp.acp_genpd->adev = adev;
263fb4d8502Sjsg
264fb4d8502Sjsg pm_genpd_init(&adev->acp.acp_genpd->gpd, NULL, false);
265*1bb76ff1Sjsg dmi_check_system(acp_quirk_table);
266*1bb76ff1Sjsg switch (acp_machine_id) {
267*1bb76ff1Sjsg case ST_JADEITE:
268*1bb76ff1Sjsg {
269*1bb76ff1Sjsg adev->acp.acp_cell = kcalloc(2, sizeof(struct mfd_cell),
270*1bb76ff1Sjsg GFP_KERNEL);
271*1bb76ff1Sjsg if (!adev->acp.acp_cell) {
272*1bb76ff1Sjsg r = -ENOMEM;
273*1bb76ff1Sjsg goto failure;
274*1bb76ff1Sjsg }
275fb4d8502Sjsg
276*1bb76ff1Sjsg adev->acp.acp_res = kcalloc(3, sizeof(struct resource), GFP_KERNEL);
277*1bb76ff1Sjsg if (!adev->acp.acp_res) {
278*1bb76ff1Sjsg r = -ENOMEM;
279*1bb76ff1Sjsg goto failure;
280*1bb76ff1Sjsg }
281*1bb76ff1Sjsg
282*1bb76ff1Sjsg i2s_pdata = kcalloc(1, sizeof(struct i2s_platform_data), GFP_KERNEL);
283*1bb76ff1Sjsg if (!i2s_pdata) {
284*1bb76ff1Sjsg r = -ENOMEM;
285*1bb76ff1Sjsg goto failure;
286*1bb76ff1Sjsg }
287*1bb76ff1Sjsg
288*1bb76ff1Sjsg i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
289*1bb76ff1Sjsg DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
290*1bb76ff1Sjsg i2s_pdata[0].cap = DWC_I2S_PLAY | DWC_I2S_RECORD;
291*1bb76ff1Sjsg i2s_pdata[0].snd_rates = SNDRV_PCM_RATE_8000_96000;
292*1bb76ff1Sjsg i2s_pdata[0].i2s_reg_comp1 = ACP_I2S_COMP1_CAP_REG_OFFSET;
293*1bb76ff1Sjsg i2s_pdata[0].i2s_reg_comp2 = ACP_I2S_COMP2_CAP_REG_OFFSET;
294*1bb76ff1Sjsg
295*1bb76ff1Sjsg adev->acp.acp_res[0].name = "acp2x_dma";
296*1bb76ff1Sjsg adev->acp.acp_res[0].flags = IORESOURCE_MEM;
297*1bb76ff1Sjsg adev->acp.acp_res[0].start = acp_base;
298*1bb76ff1Sjsg adev->acp.acp_res[0].end = acp_base + ACP_DMA_REGS_END;
299*1bb76ff1Sjsg
300*1bb76ff1Sjsg adev->acp.acp_res[1].name = "acp2x_dw_i2s_play_cap";
301*1bb76ff1Sjsg adev->acp.acp_res[1].flags = IORESOURCE_MEM;
302*1bb76ff1Sjsg adev->acp.acp_res[1].start = acp_base + ACP_I2S_CAP_REGS_START;
303*1bb76ff1Sjsg adev->acp.acp_res[1].end = acp_base + ACP_I2S_CAP_REGS_END;
304*1bb76ff1Sjsg
305*1bb76ff1Sjsg adev->acp.acp_res[2].name = "acp2x_dma_irq";
306*1bb76ff1Sjsg adev->acp.acp_res[2].flags = IORESOURCE_IRQ;
307*1bb76ff1Sjsg adev->acp.acp_res[2].start = amdgpu_irq_create_mapping(adev, 162);
308*1bb76ff1Sjsg adev->acp.acp_res[2].end = adev->acp.acp_res[2].start;
309*1bb76ff1Sjsg
310*1bb76ff1Sjsg adev->acp.acp_cell[0].name = "acp_audio_dma";
311*1bb76ff1Sjsg adev->acp.acp_cell[0].num_resources = 3;
312*1bb76ff1Sjsg adev->acp.acp_cell[0].resources = &adev->acp.acp_res[0];
313*1bb76ff1Sjsg adev->acp.acp_cell[0].platform_data = &adev->asic_type;
314*1bb76ff1Sjsg adev->acp.acp_cell[0].pdata_size = sizeof(adev->asic_type);
315*1bb76ff1Sjsg
316*1bb76ff1Sjsg adev->acp.acp_cell[1].name = "designware-i2s";
317*1bb76ff1Sjsg adev->acp.acp_cell[1].num_resources = 1;
318*1bb76ff1Sjsg adev->acp.acp_cell[1].resources = &adev->acp.acp_res[1];
319*1bb76ff1Sjsg adev->acp.acp_cell[1].platform_data = &i2s_pdata[0];
320*1bb76ff1Sjsg adev->acp.acp_cell[1].pdata_size = sizeof(struct i2s_platform_data);
321*1bb76ff1Sjsg r = mfd_add_hotplug_devices(adev->acp.parent, adev->acp.acp_cell, 2);
322*1bb76ff1Sjsg if (r)
323*1bb76ff1Sjsg goto failure;
324*1bb76ff1Sjsg r = device_for_each_child(adev->acp.parent, &adev->acp.acp_genpd->gpd,
325*1bb76ff1Sjsg acp_genpd_add_device);
326*1bb76ff1Sjsg if (r)
327*1bb76ff1Sjsg goto failure;
328*1bb76ff1Sjsg break;
329*1bb76ff1Sjsg }
330*1bb76ff1Sjsg default:
331fb4d8502Sjsg adev->acp.acp_cell = kcalloc(ACP_DEVS, sizeof(struct mfd_cell),
332fb4d8502Sjsg GFP_KERNEL);
333fb4d8502Sjsg
334*1bb76ff1Sjsg if (!adev->acp.acp_cell) {
335c349dbc7Sjsg r = -ENOMEM;
336c349dbc7Sjsg goto failure;
337c349dbc7Sjsg }
338fb4d8502Sjsg
339fb4d8502Sjsg adev->acp.acp_res = kcalloc(5, sizeof(struct resource), GFP_KERNEL);
340*1bb76ff1Sjsg if (!adev->acp.acp_res) {
341c349dbc7Sjsg r = -ENOMEM;
342c349dbc7Sjsg goto failure;
343fb4d8502Sjsg }
344fb4d8502Sjsg
345fb4d8502Sjsg i2s_pdata = kcalloc(3, sizeof(struct i2s_platform_data), GFP_KERNEL);
346*1bb76ff1Sjsg if (!i2s_pdata) {
347c349dbc7Sjsg r = -ENOMEM;
348c349dbc7Sjsg goto failure;
349fb4d8502Sjsg }
350fb4d8502Sjsg
351fb4d8502Sjsg switch (adev->asic_type) {
352fb4d8502Sjsg case CHIP_STONEY:
353fb4d8502Sjsg i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
354fb4d8502Sjsg DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
355fb4d8502Sjsg break;
356fb4d8502Sjsg default:
357fb4d8502Sjsg i2s_pdata[0].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET;
358fb4d8502Sjsg }
359fb4d8502Sjsg i2s_pdata[0].cap = DWC_I2S_PLAY;
360fb4d8502Sjsg i2s_pdata[0].snd_rates = SNDRV_PCM_RATE_8000_96000;
361fb4d8502Sjsg i2s_pdata[0].i2s_reg_comp1 = ACP_I2S_COMP1_PLAY_REG_OFFSET;
362fb4d8502Sjsg i2s_pdata[0].i2s_reg_comp2 = ACP_I2S_COMP2_PLAY_REG_OFFSET;
363fb4d8502Sjsg switch (adev->asic_type) {
364fb4d8502Sjsg case CHIP_STONEY:
365fb4d8502Sjsg i2s_pdata[1].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
366fb4d8502Sjsg DW_I2S_QUIRK_COMP_PARAM1 |
367fb4d8502Sjsg DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
368fb4d8502Sjsg break;
369fb4d8502Sjsg default:
370fb4d8502Sjsg i2s_pdata[1].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET |
371fb4d8502Sjsg DW_I2S_QUIRK_COMP_PARAM1;
372fb4d8502Sjsg }
373fb4d8502Sjsg
374fb4d8502Sjsg i2s_pdata[1].cap = DWC_I2S_RECORD;
375fb4d8502Sjsg i2s_pdata[1].snd_rates = SNDRV_PCM_RATE_8000_96000;
376fb4d8502Sjsg i2s_pdata[1].i2s_reg_comp1 = ACP_I2S_COMP1_CAP_REG_OFFSET;
377fb4d8502Sjsg i2s_pdata[1].i2s_reg_comp2 = ACP_I2S_COMP2_CAP_REG_OFFSET;
378fb4d8502Sjsg
379fb4d8502Sjsg i2s_pdata[2].quirks = DW_I2S_QUIRK_COMP_REG_OFFSET;
380fb4d8502Sjsg switch (adev->asic_type) {
381fb4d8502Sjsg case CHIP_STONEY:
382fb4d8502Sjsg i2s_pdata[2].quirks |= DW_I2S_QUIRK_16BIT_IDX_OVERRIDE;
383fb4d8502Sjsg break;
384fb4d8502Sjsg default:
385fb4d8502Sjsg break;
386fb4d8502Sjsg }
387fb4d8502Sjsg
388fb4d8502Sjsg i2s_pdata[2].cap = DWC_I2S_PLAY | DWC_I2S_RECORD;
389fb4d8502Sjsg i2s_pdata[2].snd_rates = SNDRV_PCM_RATE_8000_96000;
390fb4d8502Sjsg i2s_pdata[2].i2s_reg_comp1 = ACP_BT_COMP1_REG_OFFSET;
391fb4d8502Sjsg i2s_pdata[2].i2s_reg_comp2 = ACP_BT_COMP2_REG_OFFSET;
392fb4d8502Sjsg
393fb4d8502Sjsg adev->acp.acp_res[0].name = "acp2x_dma";
394fb4d8502Sjsg adev->acp.acp_res[0].flags = IORESOURCE_MEM;
395fb4d8502Sjsg adev->acp.acp_res[0].start = acp_base;
396fb4d8502Sjsg adev->acp.acp_res[0].end = acp_base + ACP_DMA_REGS_END;
397fb4d8502Sjsg
398fb4d8502Sjsg adev->acp.acp_res[1].name = "acp2x_dw_i2s_play";
399fb4d8502Sjsg adev->acp.acp_res[1].flags = IORESOURCE_MEM;
400fb4d8502Sjsg adev->acp.acp_res[1].start = acp_base + ACP_I2S_PLAY_REGS_START;
401fb4d8502Sjsg adev->acp.acp_res[1].end = acp_base + ACP_I2S_PLAY_REGS_END;
402fb4d8502Sjsg
403fb4d8502Sjsg adev->acp.acp_res[2].name = "acp2x_dw_i2s_cap";
404fb4d8502Sjsg adev->acp.acp_res[2].flags = IORESOURCE_MEM;
405fb4d8502Sjsg adev->acp.acp_res[2].start = acp_base + ACP_I2S_CAP_REGS_START;
406fb4d8502Sjsg adev->acp.acp_res[2].end = acp_base + ACP_I2S_CAP_REGS_END;
407fb4d8502Sjsg
408fb4d8502Sjsg adev->acp.acp_res[3].name = "acp2x_dw_bt_i2s_play_cap";
409fb4d8502Sjsg adev->acp.acp_res[3].flags = IORESOURCE_MEM;
410fb4d8502Sjsg adev->acp.acp_res[3].start = acp_base + ACP_BT_PLAY_REGS_START;
411fb4d8502Sjsg adev->acp.acp_res[3].end = acp_base + ACP_BT_PLAY_REGS_END;
412fb4d8502Sjsg
413fb4d8502Sjsg adev->acp.acp_res[4].name = "acp2x_dma_irq";
414fb4d8502Sjsg adev->acp.acp_res[4].flags = IORESOURCE_IRQ;
415fb4d8502Sjsg adev->acp.acp_res[4].start = amdgpu_irq_create_mapping(adev, 162);
416fb4d8502Sjsg adev->acp.acp_res[4].end = adev->acp.acp_res[4].start;
417fb4d8502Sjsg
418fb4d8502Sjsg adev->acp.acp_cell[0].name = "acp_audio_dma";
419fb4d8502Sjsg adev->acp.acp_cell[0].num_resources = 5;
420fb4d8502Sjsg adev->acp.acp_cell[0].resources = &adev->acp.acp_res[0];
421fb4d8502Sjsg adev->acp.acp_cell[0].platform_data = &adev->asic_type;
422fb4d8502Sjsg adev->acp.acp_cell[0].pdata_size = sizeof(adev->asic_type);
423fb4d8502Sjsg
424fb4d8502Sjsg adev->acp.acp_cell[1].name = "designware-i2s";
425fb4d8502Sjsg adev->acp.acp_cell[1].num_resources = 1;
426fb4d8502Sjsg adev->acp.acp_cell[1].resources = &adev->acp.acp_res[1];
427fb4d8502Sjsg adev->acp.acp_cell[1].platform_data = &i2s_pdata[0];
428fb4d8502Sjsg adev->acp.acp_cell[1].pdata_size = sizeof(struct i2s_platform_data);
429fb4d8502Sjsg
430fb4d8502Sjsg adev->acp.acp_cell[2].name = "designware-i2s";
431fb4d8502Sjsg adev->acp.acp_cell[2].num_resources = 1;
432fb4d8502Sjsg adev->acp.acp_cell[2].resources = &adev->acp.acp_res[2];
433fb4d8502Sjsg adev->acp.acp_cell[2].platform_data = &i2s_pdata[1];
434fb4d8502Sjsg adev->acp.acp_cell[2].pdata_size = sizeof(struct i2s_platform_data);
435fb4d8502Sjsg
436fb4d8502Sjsg adev->acp.acp_cell[3].name = "designware-i2s";
437fb4d8502Sjsg adev->acp.acp_cell[3].num_resources = 1;
438fb4d8502Sjsg adev->acp.acp_cell[3].resources = &adev->acp.acp_res[3];
439fb4d8502Sjsg adev->acp.acp_cell[3].platform_data = &i2s_pdata[2];
440fb4d8502Sjsg adev->acp.acp_cell[3].pdata_size = sizeof(struct i2s_platform_data);
441fb4d8502Sjsg
442*1bb76ff1Sjsg r = mfd_add_hotplug_devices(adev->acp.parent, adev->acp.acp_cell, ACP_DEVS);
443fb4d8502Sjsg if (r)
444c349dbc7Sjsg goto failure;
445fb4d8502Sjsg
44608718c48Sjsg r = device_for_each_child(adev->acp.parent, &adev->acp.acp_genpd->gpd,
44708718c48Sjsg acp_genpd_add_device);
44808718c48Sjsg if (r)
449c349dbc7Sjsg goto failure;
450*1bb76ff1Sjsg }
451fb4d8502Sjsg
452fb4d8502Sjsg /* Assert Soft reset of ACP */
453fb4d8502Sjsg val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
454fb4d8502Sjsg
455fb4d8502Sjsg val |= ACP_SOFT_RESET__SoftResetAud_MASK;
456fb4d8502Sjsg cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val);
457fb4d8502Sjsg
458fb4d8502Sjsg count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE;
459fb4d8502Sjsg while (true) {
460fb4d8502Sjsg val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
461fb4d8502Sjsg if (ACP_SOFT_RESET__SoftResetAudDone_MASK ==
462fb4d8502Sjsg (val & ACP_SOFT_RESET__SoftResetAudDone_MASK))
463fb4d8502Sjsg break;
464fb4d8502Sjsg if (--count == 0) {
465fb4d8502Sjsg dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
466c349dbc7Sjsg r = -ETIMEDOUT;
467c349dbc7Sjsg goto failure;
468fb4d8502Sjsg }
469fb4d8502Sjsg udelay(100);
470fb4d8502Sjsg }
471fb4d8502Sjsg /* Enable clock to ACP and wait until the clock is enabled */
472fb4d8502Sjsg val = cgs_read_register(adev->acp.cgs_device, mmACP_CONTROL);
473fb4d8502Sjsg val = val | ACP_CONTROL__ClkEn_MASK;
474fb4d8502Sjsg cgs_write_register(adev->acp.cgs_device, mmACP_CONTROL, val);
475fb4d8502Sjsg
476fb4d8502Sjsg count = ACP_CLOCK_EN_TIME_OUT_VALUE;
477fb4d8502Sjsg
478fb4d8502Sjsg while (true) {
479fb4d8502Sjsg val = cgs_read_register(adev->acp.cgs_device, mmACP_STATUS);
480fb4d8502Sjsg if (val & (u32) 0x1)
481fb4d8502Sjsg break;
482fb4d8502Sjsg if (--count == 0) {
483fb4d8502Sjsg dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
484c349dbc7Sjsg r = -ETIMEDOUT;
485c349dbc7Sjsg goto failure;
486fb4d8502Sjsg }
487fb4d8502Sjsg udelay(100);
488fb4d8502Sjsg }
489fb4d8502Sjsg /* Deassert the SOFT RESET flags */
490fb4d8502Sjsg val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
491fb4d8502Sjsg val &= ~ACP_SOFT_RESET__SoftResetAud_MASK;
492fb4d8502Sjsg cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val);
493fb4d8502Sjsg return 0;
494c349dbc7Sjsg
495c349dbc7Sjsg failure:
496c349dbc7Sjsg kfree(i2s_pdata);
497c349dbc7Sjsg kfree(adev->acp.acp_res);
498c349dbc7Sjsg kfree(adev->acp.acp_cell);
499c349dbc7Sjsg kfree(adev->acp.acp_genpd);
500c349dbc7Sjsg return r;
501fb4d8502Sjsg }
502fb4d8502Sjsg
503fb4d8502Sjsg /**
504fb4d8502Sjsg * acp_hw_fini - stop the hardware block
505fb4d8502Sjsg *
5065ca02815Sjsg * @handle: handle used to pass amdgpu_device pointer
507fb4d8502Sjsg *
508fb4d8502Sjsg */
acp_hw_fini(void * handle)509fb4d8502Sjsg static int acp_hw_fini(void *handle)
510fb4d8502Sjsg {
511fb4d8502Sjsg u32 val = 0;
512fb4d8502Sjsg u32 count = 0;
513fb4d8502Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
514fb4d8502Sjsg
515fb4d8502Sjsg /* return early if no ACP */
516c349dbc7Sjsg if (!adev->acp.acp_genpd) {
517c349dbc7Sjsg amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
518fb4d8502Sjsg return 0;
519c349dbc7Sjsg }
520fb4d8502Sjsg
521fb4d8502Sjsg /* Assert Soft reset of ACP */
522fb4d8502Sjsg val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
523fb4d8502Sjsg
524fb4d8502Sjsg val |= ACP_SOFT_RESET__SoftResetAud_MASK;
525fb4d8502Sjsg cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val);
526fb4d8502Sjsg
527fb4d8502Sjsg count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE;
528fb4d8502Sjsg while (true) {
529fb4d8502Sjsg val = cgs_read_register(adev->acp.cgs_device, mmACP_SOFT_RESET);
530fb4d8502Sjsg if (ACP_SOFT_RESET__SoftResetAudDone_MASK ==
531fb4d8502Sjsg (val & ACP_SOFT_RESET__SoftResetAudDone_MASK))
532fb4d8502Sjsg break;
533fb4d8502Sjsg if (--count == 0) {
534fb4d8502Sjsg dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
535fb4d8502Sjsg return -ETIMEDOUT;
536fb4d8502Sjsg }
537fb4d8502Sjsg udelay(100);
538fb4d8502Sjsg }
539fb4d8502Sjsg /* Disable ACP clock */
540fb4d8502Sjsg val = cgs_read_register(adev->acp.cgs_device, mmACP_CONTROL);
541fb4d8502Sjsg val &= ~ACP_CONTROL__ClkEn_MASK;
542fb4d8502Sjsg cgs_write_register(adev->acp.cgs_device, mmACP_CONTROL, val);
543fb4d8502Sjsg
544fb4d8502Sjsg count = ACP_CLOCK_EN_TIME_OUT_VALUE;
545fb4d8502Sjsg
546fb4d8502Sjsg while (true) {
547fb4d8502Sjsg val = cgs_read_register(adev->acp.cgs_device, mmACP_STATUS);
548fb4d8502Sjsg if (val & (u32) 0x1)
549fb4d8502Sjsg break;
550fb4d8502Sjsg if (--count == 0) {
551fb4d8502Sjsg dev_err(&adev->pdev->dev, "Failed to reset ACP\n");
552fb4d8502Sjsg return -ETIMEDOUT;
553fb4d8502Sjsg }
554fb4d8502Sjsg udelay(100);
555fb4d8502Sjsg }
556fb4d8502Sjsg
55708718c48Sjsg device_for_each_child(adev->acp.parent, NULL,
55808718c48Sjsg acp_genpd_remove_device);
559fb4d8502Sjsg
560fb4d8502Sjsg mfd_remove_devices(adev->acp.parent);
561fb4d8502Sjsg kfree(adev->acp.acp_res);
562c349dbc7Sjsg kfree(adev->acp.acp_genpd);
563fb4d8502Sjsg kfree(adev->acp.acp_cell);
564fb4d8502Sjsg
565fb4d8502Sjsg return 0;
566fb4d8502Sjsg }
567fb4d8502Sjsg
acp_suspend(void * handle)568fb4d8502Sjsg static int acp_suspend(void *handle)
569fb4d8502Sjsg {
570c349dbc7Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
571c349dbc7Sjsg
572c349dbc7Sjsg /* power up on suspend */
573c349dbc7Sjsg if (!adev->acp.acp_cell)
574c349dbc7Sjsg amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, false);
575fb4d8502Sjsg return 0;
576fb4d8502Sjsg }
577fb4d8502Sjsg
acp_resume(void * handle)578fb4d8502Sjsg static int acp_resume(void *handle)
579fb4d8502Sjsg {
580c349dbc7Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
581c349dbc7Sjsg
582c349dbc7Sjsg /* power down again on resume */
583c349dbc7Sjsg if (!adev->acp.acp_cell)
584c349dbc7Sjsg amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, true);
585fb4d8502Sjsg return 0;
586fb4d8502Sjsg }
587fb4d8502Sjsg
acp_early_init(void * handle)588fb4d8502Sjsg static int acp_early_init(void *handle)
589fb4d8502Sjsg {
590fb4d8502Sjsg return 0;
591fb4d8502Sjsg }
592fb4d8502Sjsg
acp_is_idle(void * handle)593fb4d8502Sjsg static bool acp_is_idle(void *handle)
594fb4d8502Sjsg {
595fb4d8502Sjsg return true;
596fb4d8502Sjsg }
597fb4d8502Sjsg
acp_wait_for_idle(void * handle)598fb4d8502Sjsg static int acp_wait_for_idle(void *handle)
599fb4d8502Sjsg {
600fb4d8502Sjsg return 0;
601fb4d8502Sjsg }
602fb4d8502Sjsg
acp_soft_reset(void * handle)603fb4d8502Sjsg static int acp_soft_reset(void *handle)
604fb4d8502Sjsg {
605fb4d8502Sjsg return 0;
606fb4d8502Sjsg }
607fb4d8502Sjsg
acp_set_clockgating_state(void * handle,enum amd_clockgating_state state)608fb4d8502Sjsg static int acp_set_clockgating_state(void *handle,
609fb4d8502Sjsg enum amd_clockgating_state state)
610fb4d8502Sjsg {
611fb4d8502Sjsg return 0;
612fb4d8502Sjsg }
613fb4d8502Sjsg
acp_set_powergating_state(void * handle,enum amd_powergating_state state)614fb4d8502Sjsg static int acp_set_powergating_state(void *handle,
615fb4d8502Sjsg enum amd_powergating_state state)
616fb4d8502Sjsg {
617c349dbc7Sjsg struct amdgpu_device *adev = (struct amdgpu_device *)handle;
618c349dbc7Sjsg bool enable = (state == AMD_PG_STATE_GATE);
619c349dbc7Sjsg
620c349dbc7Sjsg amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ACP, enable);
621c349dbc7Sjsg
622fb4d8502Sjsg return 0;
623fb4d8502Sjsg }
624fb4d8502Sjsg
625fb4d8502Sjsg static const struct amd_ip_funcs acp_ip_funcs = {
626fb4d8502Sjsg .name = "acp_ip",
627fb4d8502Sjsg .early_init = acp_early_init,
628fb4d8502Sjsg .late_init = NULL,
629fb4d8502Sjsg .sw_init = acp_sw_init,
630fb4d8502Sjsg .sw_fini = acp_sw_fini,
631fb4d8502Sjsg .hw_init = acp_hw_init,
632fb4d8502Sjsg .hw_fini = acp_hw_fini,
633fb4d8502Sjsg .suspend = acp_suspend,
634fb4d8502Sjsg .resume = acp_resume,
635fb4d8502Sjsg .is_idle = acp_is_idle,
636fb4d8502Sjsg .wait_for_idle = acp_wait_for_idle,
637fb4d8502Sjsg .soft_reset = acp_soft_reset,
638fb4d8502Sjsg .set_clockgating_state = acp_set_clockgating_state,
639fb4d8502Sjsg .set_powergating_state = acp_set_powergating_state,
640fb4d8502Sjsg };
641fb4d8502Sjsg
642*1bb76ff1Sjsg const struct amdgpu_ip_block_version acp_ip_block = {
643fb4d8502Sjsg .type = AMD_IP_BLOCK_TYPE_ACP,
644fb4d8502Sjsg .major = 2,
645fb4d8502Sjsg .minor = 2,
646fb4d8502Sjsg .rev = 0,
647fb4d8502Sjsg .funcs = &acp_ip_funcs,
648fb4d8502Sjsg };
649