1dfd57dbfSLeo Liu /*
2dfd57dbfSLeo Liu  * Copyright 2019 Advanced Micro Devices, Inc.
3dfd57dbfSLeo Liu  *
4dfd57dbfSLeo Liu  * Permission is hereby granted, free of charge, to any person obtaining a
5dfd57dbfSLeo Liu  * copy of this software and associated documentation files (the "Software"),
6dfd57dbfSLeo Liu  * to deal in the Software without restriction, including without limitation
7dfd57dbfSLeo Liu  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8dfd57dbfSLeo Liu  * and/or sell copies of the Software, and to permit persons to whom the
9dfd57dbfSLeo Liu  * Software is furnished to do so, subject to the following conditions:
10dfd57dbfSLeo Liu  *
11dfd57dbfSLeo Liu  * The above copyright notice and this permission notice shall be included in
12dfd57dbfSLeo Liu  * all copies or substantial portions of the Software.
13dfd57dbfSLeo Liu  *
14dfd57dbfSLeo Liu  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15dfd57dbfSLeo Liu  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16dfd57dbfSLeo Liu  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17dfd57dbfSLeo Liu  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18dfd57dbfSLeo Liu  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19dfd57dbfSLeo Liu  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20dfd57dbfSLeo Liu  * OTHER DEALINGS IN THE SOFTWARE.
21dfd57dbfSLeo Liu  *
22dfd57dbfSLeo Liu  */
23dfd57dbfSLeo Liu 
24dfd57dbfSLeo Liu #include "amdgpu.h"
25dfd57dbfSLeo Liu #include "amdgpu_jpeg.h"
26dfd57dbfSLeo Liu #include "amdgpu_pm.h"
27dfd57dbfSLeo Liu #include "soc15.h"
28dfd57dbfSLeo Liu #include "soc15d.h"
29dfd57dbfSLeo Liu #include "jpeg_v2_0.h"
30dfd57dbfSLeo Liu 
31dfd57dbfSLeo Liu #include "vcn/vcn_3_0_0_offset.h"
32dfd57dbfSLeo Liu #include "vcn/vcn_3_0_0_sh_mask.h"
33dfd57dbfSLeo Liu #include "ivsrcid/vcn/irqsrcs_vcn_2_0.h"
34dfd57dbfSLeo Liu 
35dfd57dbfSLeo Liu #define mmUVD_JPEG_PITCH_INTERNAL_OFFSET	0x401f
36dfd57dbfSLeo Liu 
37dfd57dbfSLeo Liu static void jpeg_v3_0_set_dec_ring_funcs(struct amdgpu_device *adev);
38dfd57dbfSLeo Liu static void jpeg_v3_0_set_irq_funcs(struct amdgpu_device *adev);
39dfd57dbfSLeo Liu static int jpeg_v3_0_set_powergating_state(void *handle,
40dfd57dbfSLeo Liu 				enum amd_powergating_state state);
41dfd57dbfSLeo Liu 
42dfd57dbfSLeo Liu /**
43dfd57dbfSLeo Liu  * jpeg_v3_0_early_init - set function pointers
44dfd57dbfSLeo Liu  *
45dfd57dbfSLeo Liu  * @handle: amdgpu_device pointer
46dfd57dbfSLeo Liu  *
47dfd57dbfSLeo Liu  * Set ring and irq function pointers
48dfd57dbfSLeo Liu  */
jpeg_v3_0_early_init(void * handle)49dfd57dbfSLeo Liu static int jpeg_v3_0_early_init(void *handle)
50dfd57dbfSLeo Liu {
51dfd57dbfSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
523d417b58SJames Zhu 
5337d6b150STim Huang 	u32 harvest;
54dfd57dbfSLeo Liu 
5537d6b150STim Huang 	switch (adev->ip_versions[UVD_HWIP][0]) {
5637d6b150STim Huang 	case IP_VERSION(3, 1, 1):
57c488a937SSaleemkhan Jamadar 	case IP_VERSION(3, 1, 2):
5837d6b150STim Huang 		break;
5937d6b150STim Huang 	default:
6037d6b150STim Huang 		harvest = RREG32_SOC15(JPEG, 0, mmCC_UVD_HARVESTING);
61dfd57dbfSLeo Liu 		if (harvest & CC_UVD_HARVESTING__UVD_DISABLE_MASK)
62dfd57dbfSLeo Liu 			return -ENOENT;
6337d6b150STim Huang 		break;
643d417b58SJames Zhu 	}
65156589f7SJames Zhu 
66dfd57dbfSLeo Liu 	adev->jpeg.num_jpeg_inst = 1;
6728bb7f13SJames Zhu 	adev->jpeg.num_jpeg_rings = 1;
68dfd57dbfSLeo Liu 
69dfd57dbfSLeo Liu 	jpeg_v3_0_set_dec_ring_funcs(adev);
70dfd57dbfSLeo Liu 	jpeg_v3_0_set_irq_funcs(adev);
71dfd57dbfSLeo Liu 
72dfd57dbfSLeo Liu 	return 0;
73dfd57dbfSLeo Liu }
74dfd57dbfSLeo Liu 
75dfd57dbfSLeo Liu /**
76dfd57dbfSLeo Liu  * jpeg_v3_0_sw_init - sw init for JPEG block
77dfd57dbfSLeo Liu  *
78dfd57dbfSLeo Liu  * @handle: amdgpu_device pointer
79dfd57dbfSLeo Liu  *
80dfd57dbfSLeo Liu  * Load firmware and sw initialization
81dfd57dbfSLeo Liu  */
jpeg_v3_0_sw_init(void * handle)82dfd57dbfSLeo Liu static int jpeg_v3_0_sw_init(void *handle)
83dfd57dbfSLeo Liu {
84dfd57dbfSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
85dfd57dbfSLeo Liu 	struct amdgpu_ring *ring;
86dfd57dbfSLeo Liu 	int r;
87dfd57dbfSLeo Liu 
88dfd57dbfSLeo Liu 	/* JPEG TRAP */
89dfd57dbfSLeo Liu 	r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN,
90dfd57dbfSLeo Liu 		VCN_2_0__SRCID__JPEG_DECODE, &adev->jpeg.inst->irq);
91dfd57dbfSLeo Liu 	if (r)
92dfd57dbfSLeo Liu 		return r;
93dfd57dbfSLeo Liu 
94dfd57dbfSLeo Liu 	r = amdgpu_jpeg_sw_init(adev);
95dfd57dbfSLeo Liu 	if (r)
96dfd57dbfSLeo Liu 		return r;
97dfd57dbfSLeo Liu 
98dfd57dbfSLeo Liu 	r = amdgpu_jpeg_resume(adev);
99dfd57dbfSLeo Liu 	if (r)
100dfd57dbfSLeo Liu 		return r;
101dfd57dbfSLeo Liu 
102bc224553SJames Zhu 	ring = adev->jpeg.inst->ring_dec;
103dfd57dbfSLeo Liu 	ring->use_doorbell = true;
104dfd57dbfSLeo Liu 	ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + 1;
105f4caf584SHawking Zhang 	ring->vm_hub = AMDGPU_MMHUB0(0);
106dfd57dbfSLeo Liu 	sprintf(ring->name, "jpeg_dec");
107dfd57dbfSLeo Liu 	r = amdgpu_ring_init(adev, ring, 512, &adev->jpeg.inst->irq, 0,
108c107171bSChristian König 			     AMDGPU_RING_PRIO_DEFAULT, NULL);
109dfd57dbfSLeo Liu 	if (r)
110dfd57dbfSLeo Liu 		return r;
111dfd57dbfSLeo Liu 
112bc224553SJames Zhu 	adev->jpeg.internal.jpeg_pitch[0] = mmUVD_JPEG_PITCH_INTERNAL_OFFSET;
113bc224553SJames Zhu 	adev->jpeg.inst->external.jpeg_pitch[0] = SOC15_REG_OFFSET(JPEG, 0, mmUVD_JPEG_PITCH);
114dfd57dbfSLeo Liu 
115dfd57dbfSLeo Liu 	return 0;
116dfd57dbfSLeo Liu }
117dfd57dbfSLeo Liu 
118dfd57dbfSLeo Liu /**
119dfd57dbfSLeo Liu  * jpeg_v3_0_sw_fini - sw fini for JPEG block
120dfd57dbfSLeo Liu  *
121dfd57dbfSLeo Liu  * @handle: amdgpu_device pointer
122dfd57dbfSLeo Liu  *
123dfd57dbfSLeo Liu  * JPEG suspend and free up sw allocation
124dfd57dbfSLeo Liu  */
jpeg_v3_0_sw_fini(void * handle)125dfd57dbfSLeo Liu static int jpeg_v3_0_sw_fini(void *handle)
126dfd57dbfSLeo Liu {
127dfd57dbfSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
128dfd57dbfSLeo Liu 	int r;
129dfd57dbfSLeo Liu 
130dfd57dbfSLeo Liu 	r = amdgpu_jpeg_suspend(adev);
131dfd57dbfSLeo Liu 	if (r)
132dfd57dbfSLeo Liu 		return r;
133dfd57dbfSLeo Liu 
134dfd57dbfSLeo Liu 	r = amdgpu_jpeg_sw_fini(adev);
135dfd57dbfSLeo Liu 
136dfd57dbfSLeo Liu 	return r;
137dfd57dbfSLeo Liu }
138dfd57dbfSLeo Liu 
139dfd57dbfSLeo Liu /**
140dfd57dbfSLeo Liu  * jpeg_v3_0_hw_init - start and test JPEG block
141dfd57dbfSLeo Liu  *
142dfd57dbfSLeo Liu  * @handle: amdgpu_device pointer
143dfd57dbfSLeo Liu  *
144dfd57dbfSLeo Liu  */
jpeg_v3_0_hw_init(void * handle)145dfd57dbfSLeo Liu static int jpeg_v3_0_hw_init(void *handle)
146dfd57dbfSLeo Liu {
147dfd57dbfSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
148bc224553SJames Zhu 	struct amdgpu_ring *ring = adev->jpeg.inst->ring_dec;
149dfd57dbfSLeo Liu 	int r;
150dfd57dbfSLeo Liu 
151dfd57dbfSLeo Liu 	adev->nbio.funcs->vcn_doorbell_range(adev, ring->use_doorbell,
152dfd57dbfSLeo Liu 		(adev->doorbell_index.vcn.vcn_ring0_1 << 1), 0);
153dfd57dbfSLeo Liu 
154dfd57dbfSLeo Liu 	r = amdgpu_ring_test_helper(ring);
155dfd57dbfSLeo Liu 	if (r)
156dfd57dbfSLeo Liu 		return r;
157dfd57dbfSLeo Liu 
158dfd57dbfSLeo Liu 	DRM_INFO("JPEG decode initialized successfully.\n");
159dfd57dbfSLeo Liu 
160dfd57dbfSLeo Liu 	return 0;
161dfd57dbfSLeo Liu }
162dfd57dbfSLeo Liu 
163dfd57dbfSLeo Liu /**
164dfd57dbfSLeo Liu  * jpeg_v3_0_hw_fini - stop the hardware block
165dfd57dbfSLeo Liu  *
166dfd57dbfSLeo Liu  * @handle: amdgpu_device pointer
167dfd57dbfSLeo Liu  *
168dfd57dbfSLeo Liu  * Stop the JPEG block, mark ring as not ready any more
169dfd57dbfSLeo Liu  */
jpeg_v3_0_hw_fini(void * handle)170dfd57dbfSLeo Liu static int jpeg_v3_0_hw_fini(void *handle)
171dfd57dbfSLeo Liu {
172dfd57dbfSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
173dfd57dbfSLeo Liu 
174223ce1d5SJames Zhu 	cancel_delayed_work_sync(&adev->vcn.idle_work);
175223ce1d5SJames Zhu 
176dfd57dbfSLeo Liu 	if (adev->jpeg.cur_state != AMD_PG_STATE_GATE &&
177dfd57dbfSLeo Liu 	      RREG32_SOC15(JPEG, 0, mmUVD_JRBC_STATUS))
178dfd57dbfSLeo Liu 		jpeg_v3_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
179dfd57dbfSLeo Liu 
180dfd57dbfSLeo Liu 	return 0;
181dfd57dbfSLeo Liu }
182dfd57dbfSLeo Liu 
183dfd57dbfSLeo Liu /**
184dfd57dbfSLeo Liu  * jpeg_v3_0_suspend - suspend JPEG block
185dfd57dbfSLeo Liu  *
186dfd57dbfSLeo Liu  * @handle: amdgpu_device pointer
187dfd57dbfSLeo Liu  *
188dfd57dbfSLeo Liu  * HW fini and suspend JPEG block
189dfd57dbfSLeo Liu  */
jpeg_v3_0_suspend(void * handle)190dfd57dbfSLeo Liu static int jpeg_v3_0_suspend(void *handle)
191dfd57dbfSLeo Liu {
192dfd57dbfSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
193dfd57dbfSLeo Liu 	int r;
194dfd57dbfSLeo Liu 
195dfd57dbfSLeo Liu 	r = jpeg_v3_0_hw_fini(adev);
196dfd57dbfSLeo Liu 	if (r)
197dfd57dbfSLeo Liu 		return r;
198dfd57dbfSLeo Liu 
199dfd57dbfSLeo Liu 	r = amdgpu_jpeg_suspend(adev);
200dfd57dbfSLeo Liu 
201dfd57dbfSLeo Liu 	return r;
202dfd57dbfSLeo Liu }
203dfd57dbfSLeo Liu 
204dfd57dbfSLeo Liu /**
205dfd57dbfSLeo Liu  * jpeg_v3_0_resume - resume JPEG block
206dfd57dbfSLeo Liu  *
207dfd57dbfSLeo Liu  * @handle: amdgpu_device pointer
208dfd57dbfSLeo Liu  *
209dfd57dbfSLeo Liu  * Resume firmware and hw init JPEG block
210dfd57dbfSLeo Liu  */
jpeg_v3_0_resume(void * handle)211dfd57dbfSLeo Liu static int jpeg_v3_0_resume(void *handle)
212dfd57dbfSLeo Liu {
213dfd57dbfSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
214dfd57dbfSLeo Liu 	int r;
215dfd57dbfSLeo Liu 
216dfd57dbfSLeo Liu 	r = amdgpu_jpeg_resume(adev);
217dfd57dbfSLeo Liu 	if (r)
218dfd57dbfSLeo Liu 		return r;
219dfd57dbfSLeo Liu 
220dfd57dbfSLeo Liu 	r = jpeg_v3_0_hw_init(adev);
221dfd57dbfSLeo Liu 
222dfd57dbfSLeo Liu 	return r;
223dfd57dbfSLeo Liu }
224dfd57dbfSLeo Liu 
jpeg_v3_0_disable_clock_gating(struct amdgpu_device * adev)225b52e271eSLeo Liu static void jpeg_v3_0_disable_clock_gating(struct amdgpu_device *adev)
226b52e271eSLeo Liu {
227b52e271eSLeo Liu 	uint32_t data = 0;
228b52e271eSLeo Liu 
229b52e271eSLeo Liu 	data = RREG32_SOC15(JPEG, 0, mmJPEG_CGC_CTRL);
230b52e271eSLeo Liu 	if (adev->cg_flags & AMD_CG_SUPPORT_JPEG_MGCG)
231b52e271eSLeo Liu 		data |= 1 << JPEG_CGC_CTRL__DYN_CLOCK_MODE__SHIFT;
232b52e271eSLeo Liu 	else
233b52e271eSLeo Liu 		data &= ~JPEG_CGC_CTRL__DYN_CLOCK_MODE__SHIFT;
234b52e271eSLeo Liu 
235b52e271eSLeo Liu 	data |= 1 << JPEG_CGC_CTRL__CLK_GATE_DLY_TIMER__SHIFT;
236b52e271eSLeo Liu 	data |= 4 << JPEG_CGC_CTRL__CLK_OFF_DELAY__SHIFT;
237b52e271eSLeo Liu 	WREG32_SOC15(JPEG, 0, mmJPEG_CGC_CTRL, data);
238b52e271eSLeo Liu 
239b52e271eSLeo Liu 	data = RREG32_SOC15(JPEG, 0, mmJPEG_CGC_GATE);
240b52e271eSLeo Liu 	data &= ~(JPEG_CGC_GATE__JPEG_DEC_MASK
241b52e271eSLeo Liu 		| JPEG_CGC_GATE__JPEG2_DEC_MASK
242b52e271eSLeo Liu 		| JPEG_CGC_GATE__JPEG_ENC_MASK
243b52e271eSLeo Liu 		| JPEG_CGC_GATE__JMCIF_MASK
244b52e271eSLeo Liu 		| JPEG_CGC_GATE__JRBBM_MASK);
245b52e271eSLeo Liu 	WREG32_SOC15(JPEG, 0, mmJPEG_CGC_GATE, data);
246b52e271eSLeo Liu 
247b52e271eSLeo Liu 	data = RREG32_SOC15(JPEG, 0, mmJPEG_CGC_CTRL);
248b52e271eSLeo Liu 	data &= ~(JPEG_CGC_CTRL__JPEG_DEC_MODE_MASK
249b52e271eSLeo Liu 		| JPEG_CGC_CTRL__JPEG2_DEC_MODE_MASK
250b52e271eSLeo Liu 		| JPEG_CGC_CTRL__JMCIF_MODE_MASK
251b52e271eSLeo Liu 		| JPEG_CGC_CTRL__JRBBM_MODE_MASK);
252b52e271eSLeo Liu 	WREG32_SOC15(JPEG, 0, mmJPEG_CGC_CTRL, data);
253b52e271eSLeo Liu }
254b52e271eSLeo Liu 
jpeg_v3_0_enable_clock_gating(struct amdgpu_device * adev)255b52e271eSLeo Liu static void jpeg_v3_0_enable_clock_gating(struct amdgpu_device *adev)
256b52e271eSLeo Liu {
257b52e271eSLeo Liu 	uint32_t data = 0;
258b52e271eSLeo Liu 
259b52e271eSLeo Liu 	data = RREG32_SOC15(JPEG, 0, mmJPEG_CGC_GATE);
260b52e271eSLeo Liu 	data |= (JPEG_CGC_GATE__JPEG_DEC_MASK
261b52e271eSLeo Liu 		|JPEG_CGC_GATE__JPEG2_DEC_MASK
262b52e271eSLeo Liu 		|JPEG_CGC_GATE__JPEG_ENC_MASK
263b52e271eSLeo Liu 		|JPEG_CGC_GATE__JMCIF_MASK
264b52e271eSLeo Liu 		|JPEG_CGC_GATE__JRBBM_MASK);
265b52e271eSLeo Liu 	WREG32_SOC15(JPEG, 0, mmJPEG_CGC_GATE, data);
266b52e271eSLeo Liu }
267b52e271eSLeo Liu 
jpeg_v3_0_disable_static_power_gating(struct amdgpu_device * adev)268b52e271eSLeo Liu static int jpeg_v3_0_disable_static_power_gating(struct amdgpu_device *adev)
269b52e271eSLeo Liu {
270b52e271eSLeo Liu 	if (adev->pg_flags & AMD_PG_SUPPORT_JPEG) {
271b52e271eSLeo Liu 		uint32_t data = 0;
272b52e271eSLeo Liu 		int r = 0;
273b52e271eSLeo Liu 
274b52e271eSLeo Liu 		data = 1 << UVD_PGFSM_CONFIG__UVDJ_PWR_CONFIG__SHIFT;
275b52e271eSLeo Liu 		WREG32(SOC15_REG_OFFSET(JPEG, 0, mmUVD_PGFSM_CONFIG), data);
276b52e271eSLeo Liu 
277450da2efSJames Zhu 		r = SOC15_WAIT_ON_RREG(JPEG, 0,
278b52e271eSLeo Liu 			mmUVD_PGFSM_STATUS, UVD_PGFSM_STATUS_UVDJ_PWR_ON,
279450da2efSJames Zhu 			UVD_PGFSM_STATUS__UVDJ_PWR_STATUS_MASK);
280b52e271eSLeo Liu 
281b52e271eSLeo Liu 		if (r) {
282b52e271eSLeo Liu 			DRM_ERROR("amdgpu: JPEG disable power gating failed\n");
283b52e271eSLeo Liu 			return r;
284b52e271eSLeo Liu 		}
285b52e271eSLeo Liu 	}
286b52e271eSLeo Liu 
287b52e271eSLeo Liu 	/* disable anti hang mechanism */
288b52e271eSLeo Liu 	WREG32_P(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JPEG_POWER_STATUS), 0,
289b52e271eSLeo Liu 		~UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK);
290b52e271eSLeo Liu 
291b52e271eSLeo Liu 	/* keep the JPEG in static PG mode */
292b52e271eSLeo Liu 	WREG32_P(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JPEG_POWER_STATUS), 0,
293b52e271eSLeo Liu 		~UVD_JPEG_POWER_STATUS__JPEG_PG_MODE_MASK);
294b52e271eSLeo Liu 
295b52e271eSLeo Liu 	return 0;
296b52e271eSLeo Liu }
297b52e271eSLeo Liu 
jpeg_v3_0_enable_static_power_gating(struct amdgpu_device * adev)298b52e271eSLeo Liu static int jpeg_v3_0_enable_static_power_gating(struct amdgpu_device *adev)
299b52e271eSLeo Liu {
300b52e271eSLeo Liu 	/* enable anti hang mechanism */
301b52e271eSLeo Liu 	WREG32_P(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JPEG_POWER_STATUS),
302b52e271eSLeo Liu 		UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK,
303b52e271eSLeo Liu 		~UVD_JPEG_POWER_STATUS__JPEG_POWER_STATUS_MASK);
304b52e271eSLeo Liu 
305b52e271eSLeo Liu 	if (adev->pg_flags & AMD_PG_SUPPORT_JPEG) {
306b52e271eSLeo Liu 		uint32_t data = 0;
307b52e271eSLeo Liu 		int r = 0;
308b52e271eSLeo Liu 
309b52e271eSLeo Liu 		data = 2 << UVD_PGFSM_CONFIG__UVDJ_PWR_CONFIG__SHIFT;
310b52e271eSLeo Liu 		WREG32(SOC15_REG_OFFSET(JPEG, 0, mmUVD_PGFSM_CONFIG), data);
311b52e271eSLeo Liu 
312450da2efSJames Zhu 		r = SOC15_WAIT_ON_RREG(JPEG, 0, mmUVD_PGFSM_STATUS,
313b52e271eSLeo Liu 			(2 << UVD_PGFSM_STATUS__UVDJ_PWR_STATUS__SHIFT),
314450da2efSJames Zhu 			UVD_PGFSM_STATUS__UVDJ_PWR_STATUS_MASK);
315b52e271eSLeo Liu 
316b52e271eSLeo Liu 		if (r) {
317b52e271eSLeo Liu 			DRM_ERROR("amdgpu: JPEG enable power gating failed\n");
318b52e271eSLeo Liu 			return r;
319b52e271eSLeo Liu 		}
320b52e271eSLeo Liu 	}
321b52e271eSLeo Liu 
322b52e271eSLeo Liu 	return 0;
323b52e271eSLeo Liu }
324b52e271eSLeo Liu 
325dfd57dbfSLeo Liu /**
326dfd57dbfSLeo Liu  * jpeg_v3_0_start - start JPEG block
327dfd57dbfSLeo Liu  *
328dfd57dbfSLeo Liu  * @adev: amdgpu_device pointer
329dfd57dbfSLeo Liu  *
330dfd57dbfSLeo Liu  * Setup and start the JPEG block
331dfd57dbfSLeo Liu  */
jpeg_v3_0_start(struct amdgpu_device * adev)332dfd57dbfSLeo Liu static int jpeg_v3_0_start(struct amdgpu_device *adev)
333dfd57dbfSLeo Liu {
334bc224553SJames Zhu 	struct amdgpu_ring *ring = adev->jpeg.inst->ring_dec;
335b52e271eSLeo Liu 	int r;
336dfd57dbfSLeo Liu 
337dfd57dbfSLeo Liu 	if (adev->pm.dpm_enabled)
338dfd57dbfSLeo Liu 		amdgpu_dpm_enable_jpeg(adev, true);
339dfd57dbfSLeo Liu 
340b52e271eSLeo Liu 	/* disable power gating */
341b52e271eSLeo Liu 	r = jpeg_v3_0_disable_static_power_gating(adev);
342b52e271eSLeo Liu 	if (r)
343b52e271eSLeo Liu 		return r;
344b52e271eSLeo Liu 
345b52e271eSLeo Liu 	/* JPEG disable CGC */
346b52e271eSLeo Liu 	jpeg_v3_0_disable_clock_gating(adev);
347b52e271eSLeo Liu 
348dfd57dbfSLeo Liu 	/* MJPEG global tiling registers */
349dfd57dbfSLeo Liu 	WREG32_SOC15(JPEG, 0, mmJPEG_DEC_GFX10_ADDR_CONFIG,
350dfd57dbfSLeo Liu 		adev->gfx.config.gb_addr_config);
351dfd57dbfSLeo Liu 	WREG32_SOC15(JPEG, 0, mmJPEG_ENC_GFX10_ADDR_CONFIG,
352dfd57dbfSLeo Liu 		adev->gfx.config.gb_addr_config);
353dfd57dbfSLeo Liu 
354dfd57dbfSLeo Liu 	/* enable JMI channel */
355dfd57dbfSLeo Liu 	WREG32_P(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JMI_CNTL), 0,
356dfd57dbfSLeo Liu 		~UVD_JMI_CNTL__SOFT_RESET_MASK);
357dfd57dbfSLeo Liu 
358dfd57dbfSLeo Liu 	/* enable System Interrupt for JRBC */
359dfd57dbfSLeo Liu 	WREG32_P(SOC15_REG_OFFSET(JPEG, 0, mmJPEG_SYS_INT_EN),
360dfd57dbfSLeo Liu 		JPEG_SYS_INT_EN__DJRBC_MASK,
361dfd57dbfSLeo Liu 		~JPEG_SYS_INT_EN__DJRBC_MASK);
362dfd57dbfSLeo Liu 
363dfd57dbfSLeo Liu 	WREG32_SOC15(JPEG, 0, mmUVD_LMI_JRBC_RB_VMID, 0);
364dfd57dbfSLeo Liu 	WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_CNTL, (0x00000001L | 0x00000002L));
365dfd57dbfSLeo Liu 	WREG32_SOC15(JPEG, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_LOW,
366dfd57dbfSLeo Liu 		lower_32_bits(ring->gpu_addr));
367dfd57dbfSLeo Liu 	WREG32_SOC15(JPEG, 0, mmUVD_LMI_JRBC_RB_64BIT_BAR_HIGH,
368dfd57dbfSLeo Liu 		upper_32_bits(ring->gpu_addr));
369dfd57dbfSLeo Liu 	WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_RPTR, 0);
370dfd57dbfSLeo Liu 	WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_WPTR, 0);
371dfd57dbfSLeo Liu 	WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_CNTL, 0x00000002L);
372dfd57dbfSLeo Liu 	WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_SIZE, ring->ring_size / 4);
373dfd57dbfSLeo Liu 	ring->wptr = RREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_WPTR);
374dfd57dbfSLeo Liu 
375dfd57dbfSLeo Liu 	return 0;
376dfd57dbfSLeo Liu }
377dfd57dbfSLeo Liu 
378dfd57dbfSLeo Liu /**
379dfd57dbfSLeo Liu  * jpeg_v3_0_stop - stop JPEG block
380dfd57dbfSLeo Liu  *
381dfd57dbfSLeo Liu  * @adev: amdgpu_device pointer
382dfd57dbfSLeo Liu  *
383dfd57dbfSLeo Liu  * stop the JPEG block
384dfd57dbfSLeo Liu  */
jpeg_v3_0_stop(struct amdgpu_device * adev)385dfd57dbfSLeo Liu static int jpeg_v3_0_stop(struct amdgpu_device *adev)
386dfd57dbfSLeo Liu {
387b52e271eSLeo Liu 	int r;
388b52e271eSLeo Liu 
389dfd57dbfSLeo Liu 	/* reset JMI */
390dfd57dbfSLeo Liu 	WREG32_P(SOC15_REG_OFFSET(JPEG, 0, mmUVD_JMI_CNTL),
391dfd57dbfSLeo Liu 		UVD_JMI_CNTL__SOFT_RESET_MASK,
392dfd57dbfSLeo Liu 		~UVD_JMI_CNTL__SOFT_RESET_MASK);
393dfd57dbfSLeo Liu 
394b52e271eSLeo Liu 	jpeg_v3_0_enable_clock_gating(adev);
395b52e271eSLeo Liu 
396b52e271eSLeo Liu 	/* enable power gating */
397b52e271eSLeo Liu 	r = jpeg_v3_0_enable_static_power_gating(adev);
398b52e271eSLeo Liu 	if (r)
399b52e271eSLeo Liu 		return r;
400b52e271eSLeo Liu 
401dfd57dbfSLeo Liu 	if (adev->pm.dpm_enabled)
402dfd57dbfSLeo Liu 		amdgpu_dpm_enable_jpeg(adev, false);
403dfd57dbfSLeo Liu 
404dfd57dbfSLeo Liu 	return 0;
405dfd57dbfSLeo Liu }
406dfd57dbfSLeo Liu 
407dfd57dbfSLeo Liu /**
408dfd57dbfSLeo Liu  * jpeg_v3_0_dec_ring_get_rptr - get read pointer
409dfd57dbfSLeo Liu  *
410dfd57dbfSLeo Liu  * @ring: amdgpu_ring pointer
411dfd57dbfSLeo Liu  *
412dfd57dbfSLeo Liu  * Returns the current hardware read pointer
413dfd57dbfSLeo Liu  */
jpeg_v3_0_dec_ring_get_rptr(struct amdgpu_ring * ring)414dfd57dbfSLeo Liu static uint64_t jpeg_v3_0_dec_ring_get_rptr(struct amdgpu_ring *ring)
415dfd57dbfSLeo Liu {
416dfd57dbfSLeo Liu 	struct amdgpu_device *adev = ring->adev;
417dfd57dbfSLeo Liu 
418dfd57dbfSLeo Liu 	return RREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_RPTR);
419dfd57dbfSLeo Liu }
420dfd57dbfSLeo Liu 
421dfd57dbfSLeo Liu /**
422dfd57dbfSLeo Liu  * jpeg_v3_0_dec_ring_get_wptr - get write pointer
423dfd57dbfSLeo Liu  *
424dfd57dbfSLeo Liu  * @ring: amdgpu_ring pointer
425dfd57dbfSLeo Liu  *
426dfd57dbfSLeo Liu  * Returns the current hardware write pointer
427dfd57dbfSLeo Liu  */
jpeg_v3_0_dec_ring_get_wptr(struct amdgpu_ring * ring)428dfd57dbfSLeo Liu static uint64_t jpeg_v3_0_dec_ring_get_wptr(struct amdgpu_ring *ring)
429dfd57dbfSLeo Liu {
430dfd57dbfSLeo Liu 	struct amdgpu_device *adev = ring->adev;
431dfd57dbfSLeo Liu 
432dfd57dbfSLeo Liu 	if (ring->use_doorbell)
4333748424bSJack Xiao 		return *ring->wptr_cpu_addr;
434dfd57dbfSLeo Liu 	else
435dfd57dbfSLeo Liu 		return RREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_WPTR);
436dfd57dbfSLeo Liu }
437dfd57dbfSLeo Liu 
438dfd57dbfSLeo Liu /**
439dfd57dbfSLeo Liu  * jpeg_v3_0_dec_ring_set_wptr - set write pointer
440dfd57dbfSLeo Liu  *
441dfd57dbfSLeo Liu  * @ring: amdgpu_ring pointer
442dfd57dbfSLeo Liu  *
443dfd57dbfSLeo Liu  * Commits the write pointer to the hardware
444dfd57dbfSLeo Liu  */
jpeg_v3_0_dec_ring_set_wptr(struct amdgpu_ring * ring)445dfd57dbfSLeo Liu static void jpeg_v3_0_dec_ring_set_wptr(struct amdgpu_ring *ring)
446dfd57dbfSLeo Liu {
447dfd57dbfSLeo Liu 	struct amdgpu_device *adev = ring->adev;
448dfd57dbfSLeo Liu 
449dfd57dbfSLeo Liu 	if (ring->use_doorbell) {
4503748424bSJack Xiao 		*ring->wptr_cpu_addr = lower_32_bits(ring->wptr);
451dfd57dbfSLeo Liu 		WDOORBELL32(ring->doorbell_index, lower_32_bits(ring->wptr));
452dfd57dbfSLeo Liu 	} else {
453dfd57dbfSLeo Liu 		WREG32_SOC15(JPEG, 0, mmUVD_JRBC_RB_WPTR, lower_32_bits(ring->wptr));
454dfd57dbfSLeo Liu 	}
455dfd57dbfSLeo Liu }
456dfd57dbfSLeo Liu 
jpeg_v3_0_is_idle(void * handle)457dfd57dbfSLeo Liu static bool jpeg_v3_0_is_idle(void *handle)
458dfd57dbfSLeo Liu {
459dfd57dbfSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
460dfd57dbfSLeo Liu 	int ret = 1;
461dfd57dbfSLeo Liu 
462dfd57dbfSLeo Liu 	ret &= (((RREG32_SOC15(JPEG, 0, mmUVD_JRBC_STATUS) &
463dfd57dbfSLeo Liu 		UVD_JRBC_STATUS__RB_JOB_DONE_MASK) ==
464dfd57dbfSLeo Liu 		UVD_JRBC_STATUS__RB_JOB_DONE_MASK));
465dfd57dbfSLeo Liu 
466dfd57dbfSLeo Liu 	return ret;
467dfd57dbfSLeo Liu }
468dfd57dbfSLeo Liu 
jpeg_v3_0_wait_for_idle(void * handle)469dfd57dbfSLeo Liu static int jpeg_v3_0_wait_for_idle(void *handle)
470dfd57dbfSLeo Liu {
471dfd57dbfSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
472dfd57dbfSLeo Liu 
473cdab4211SLeo Liu 	return SOC15_WAIT_ON_RREG(JPEG, 0, mmUVD_JRBC_STATUS,
474dfd57dbfSLeo Liu 		UVD_JRBC_STATUS__RB_JOB_DONE_MASK,
475450da2efSJames Zhu 		UVD_JRBC_STATUS__RB_JOB_DONE_MASK);
476dfd57dbfSLeo Liu }
477dfd57dbfSLeo Liu 
jpeg_v3_0_set_clockgating_state(void * handle,enum amd_clockgating_state state)478dfd57dbfSLeo Liu static int jpeg_v3_0_set_clockgating_state(void *handle,
479dfd57dbfSLeo Liu 					  enum amd_clockgating_state state)
480dfd57dbfSLeo Liu {
481b52e271eSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
482*3b780089SRuan Jinjie 	bool enable = state == AMD_CG_STATE_GATE;
483b52e271eSLeo Liu 
484b52e271eSLeo Liu 	if (enable) {
485df3183b3SJames Zhu 		if (!jpeg_v3_0_is_idle(handle))
486b52e271eSLeo Liu 			return -EBUSY;
487b52e271eSLeo Liu 		jpeg_v3_0_enable_clock_gating(adev);
488b52e271eSLeo Liu 	} else {
489b52e271eSLeo Liu 		jpeg_v3_0_disable_clock_gating(adev);
490b52e271eSLeo Liu 	}
491b52e271eSLeo Liu 
492dfd57dbfSLeo Liu 	return 0;
493dfd57dbfSLeo Liu }
494dfd57dbfSLeo Liu 
jpeg_v3_0_set_powergating_state(void * handle,enum amd_powergating_state state)495dfd57dbfSLeo Liu static int jpeg_v3_0_set_powergating_state(void *handle,
496dfd57dbfSLeo Liu 					  enum amd_powergating_state state)
497dfd57dbfSLeo Liu {
498dfd57dbfSLeo Liu 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
499dfd57dbfSLeo Liu 	int ret;
500dfd57dbfSLeo Liu 
501dfd57dbfSLeo Liu 	if(state == adev->jpeg.cur_state)
502dfd57dbfSLeo Liu 		return 0;
503dfd57dbfSLeo Liu 
504dfd57dbfSLeo Liu 	if (state == AMD_PG_STATE_GATE)
505dfd57dbfSLeo Liu 		ret = jpeg_v3_0_stop(adev);
506dfd57dbfSLeo Liu 	else
507dfd57dbfSLeo Liu 		ret = jpeg_v3_0_start(adev);
508dfd57dbfSLeo Liu 
509dfd57dbfSLeo Liu 	if(!ret)
510dfd57dbfSLeo Liu 		adev->jpeg.cur_state = state;
511dfd57dbfSLeo Liu 
512dfd57dbfSLeo Liu 	return ret;
513dfd57dbfSLeo Liu }
514dfd57dbfSLeo Liu 
jpeg_v3_0_set_interrupt_state(struct amdgpu_device * adev,struct amdgpu_irq_src * source,unsigned type,enum amdgpu_interrupt_state state)515dfd57dbfSLeo Liu static int jpeg_v3_0_set_interrupt_state(struct amdgpu_device *adev,
516dfd57dbfSLeo Liu 					struct amdgpu_irq_src *source,
517dfd57dbfSLeo Liu 					unsigned type,
518dfd57dbfSLeo Liu 					enum amdgpu_interrupt_state state)
519dfd57dbfSLeo Liu {
520dfd57dbfSLeo Liu 	return 0;
521dfd57dbfSLeo Liu }
522dfd57dbfSLeo Liu 
jpeg_v3_0_process_interrupt(struct amdgpu_device * adev,struct amdgpu_irq_src * source,struct amdgpu_iv_entry * entry)523dfd57dbfSLeo Liu static int jpeg_v3_0_process_interrupt(struct amdgpu_device *adev,
524dfd57dbfSLeo Liu 				      struct amdgpu_irq_src *source,
525dfd57dbfSLeo Liu 				      struct amdgpu_iv_entry *entry)
526dfd57dbfSLeo Liu {
527dfd57dbfSLeo Liu 	DRM_DEBUG("IH: JPEG TRAP\n");
528dfd57dbfSLeo Liu 
529dfd57dbfSLeo Liu 	switch (entry->src_id) {
530dfd57dbfSLeo Liu 	case VCN_2_0__SRCID__JPEG_DECODE:
531bc224553SJames Zhu 		amdgpu_fence_process(adev->jpeg.inst->ring_dec);
532dfd57dbfSLeo Liu 		break;
533dfd57dbfSLeo Liu 	default:
534dfd57dbfSLeo Liu 		DRM_ERROR("Unhandled interrupt: %d %d\n",
535dfd57dbfSLeo Liu 			  entry->src_id, entry->src_data[0]);
536dfd57dbfSLeo Liu 		break;
537dfd57dbfSLeo Liu 	}
538dfd57dbfSLeo Liu 
539dfd57dbfSLeo Liu 	return 0;
540dfd57dbfSLeo Liu }
541dfd57dbfSLeo Liu 
542dfd57dbfSLeo Liu static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = {
543dfd57dbfSLeo Liu 	.name = "jpeg_v3_0",
544dfd57dbfSLeo Liu 	.early_init = jpeg_v3_0_early_init,
545dfd57dbfSLeo Liu 	.late_init = NULL,
546dfd57dbfSLeo Liu 	.sw_init = jpeg_v3_0_sw_init,
547dfd57dbfSLeo Liu 	.sw_fini = jpeg_v3_0_sw_fini,
548dfd57dbfSLeo Liu 	.hw_init = jpeg_v3_0_hw_init,
549dfd57dbfSLeo Liu 	.hw_fini = jpeg_v3_0_hw_fini,
550dfd57dbfSLeo Liu 	.suspend = jpeg_v3_0_suspend,
551dfd57dbfSLeo Liu 	.resume = jpeg_v3_0_resume,
552dfd57dbfSLeo Liu 	.is_idle = jpeg_v3_0_is_idle,
553dfd57dbfSLeo Liu 	.wait_for_idle = jpeg_v3_0_wait_for_idle,
554dfd57dbfSLeo Liu 	.check_soft_reset = NULL,
555dfd57dbfSLeo Liu 	.pre_soft_reset = NULL,
556dfd57dbfSLeo Liu 	.soft_reset = NULL,
557dfd57dbfSLeo Liu 	.post_soft_reset = NULL,
558dfd57dbfSLeo Liu 	.set_clockgating_state = jpeg_v3_0_set_clockgating_state,
559dfd57dbfSLeo Liu 	.set_powergating_state = jpeg_v3_0_set_powergating_state,
560dfd57dbfSLeo Liu };
561dfd57dbfSLeo Liu 
562dfd57dbfSLeo Liu static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = {
563dfd57dbfSLeo Liu 	.type = AMDGPU_RING_TYPE_VCN_JPEG,
564dfd57dbfSLeo Liu 	.align_mask = 0xf,
565dfd57dbfSLeo Liu 	.get_rptr = jpeg_v3_0_dec_ring_get_rptr,
566dfd57dbfSLeo Liu 	.get_wptr = jpeg_v3_0_dec_ring_get_wptr,
567dfd57dbfSLeo Liu 	.set_wptr = jpeg_v3_0_dec_ring_set_wptr,
568dfd57dbfSLeo Liu 	.emit_frame_size =
569dfd57dbfSLeo Liu 		SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 +
570dfd57dbfSLeo Liu 		SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 +
571dfd57dbfSLeo Liu 		8 + /* jpeg_v3_0_dec_ring_emit_vm_flush */
572dfd57dbfSLeo Liu 		18 + 18 + /* jpeg_v3_0_dec_ring_emit_fence x2 vm fence */
573dfd57dbfSLeo Liu 		8 + 16,
574dfd57dbfSLeo Liu 	.emit_ib_size = 22, /* jpeg_v3_0_dec_ring_emit_ib */
575dfd57dbfSLeo Liu 	.emit_ib = jpeg_v2_0_dec_ring_emit_ib,
576dfd57dbfSLeo Liu 	.emit_fence = jpeg_v2_0_dec_ring_emit_fence,
577dfd57dbfSLeo Liu 	.emit_vm_flush = jpeg_v2_0_dec_ring_emit_vm_flush,
578dfd57dbfSLeo Liu 	.test_ring = amdgpu_jpeg_dec_ring_test_ring,
579dfd57dbfSLeo Liu 	.test_ib = amdgpu_jpeg_dec_ring_test_ib,
580dfd57dbfSLeo Liu 	.insert_nop = jpeg_v2_0_dec_ring_nop,
581dfd57dbfSLeo Liu 	.insert_start = jpeg_v2_0_dec_ring_insert_start,
582dfd57dbfSLeo Liu 	.insert_end = jpeg_v2_0_dec_ring_insert_end,
583dfd57dbfSLeo Liu 	.pad_ib = amdgpu_ring_generic_pad_ib,
584dfd57dbfSLeo Liu 	.begin_use = amdgpu_jpeg_ring_begin_use,
585dfd57dbfSLeo Liu 	.end_use = amdgpu_jpeg_ring_end_use,
586dfd57dbfSLeo Liu 	.emit_wreg = jpeg_v2_0_dec_ring_emit_wreg,
587dfd57dbfSLeo Liu 	.emit_reg_wait = jpeg_v2_0_dec_ring_emit_reg_wait,
588dfd57dbfSLeo Liu 	.emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper,
589dfd57dbfSLeo Liu };
590dfd57dbfSLeo Liu 
jpeg_v3_0_set_dec_ring_funcs(struct amdgpu_device * adev)591dfd57dbfSLeo Liu static void jpeg_v3_0_set_dec_ring_funcs(struct amdgpu_device *adev)
592dfd57dbfSLeo Liu {
593bc224553SJames Zhu 	adev->jpeg.inst->ring_dec->funcs = &jpeg_v3_0_dec_ring_vm_funcs;
594dfd57dbfSLeo Liu 	DRM_INFO("JPEG decode is enabled in VM mode\n");
595dfd57dbfSLeo Liu }
596dfd57dbfSLeo Liu 
597dfd57dbfSLeo Liu static const struct amdgpu_irq_src_funcs jpeg_v3_0_irq_funcs = {
598dfd57dbfSLeo Liu 	.set = jpeg_v3_0_set_interrupt_state,
599dfd57dbfSLeo Liu 	.process = jpeg_v3_0_process_interrupt,
600dfd57dbfSLeo Liu };
601dfd57dbfSLeo Liu 
jpeg_v3_0_set_irq_funcs(struct amdgpu_device * adev)602dfd57dbfSLeo Liu static void jpeg_v3_0_set_irq_funcs(struct amdgpu_device *adev)
603dfd57dbfSLeo Liu {
604dfd57dbfSLeo Liu 	adev->jpeg.inst->irq.num_types = 1;
605dfd57dbfSLeo Liu 	adev->jpeg.inst->irq.funcs = &jpeg_v3_0_irq_funcs;
606dfd57dbfSLeo Liu }
607dfd57dbfSLeo Liu 
608dfd57dbfSLeo Liu const struct amdgpu_ip_block_version jpeg_v3_0_ip_block =
609dfd57dbfSLeo Liu {
610dfd57dbfSLeo Liu 	.type = AMD_IP_BLOCK_TYPE_JPEG,
611dfd57dbfSLeo Liu 	.major = 3,
612dfd57dbfSLeo Liu 	.minor = 0,
613dfd57dbfSLeo Liu 	.rev = 0,
614dfd57dbfSLeo Liu 	.funcs = &jpeg_v3_0_ip_funcs,
615dfd57dbfSLeo Liu };
616