xref: /openbsd-src/sys/dev/pci/drm/amd/amdgpu/amdgpu_acp.c (revision 1bb76ff151c0aba8e3312a604e4cd2e5195cf4b7)
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