188dfc9a3SLikun Gao /*
288dfc9a3SLikun Gao  * Copyright 2014 Advanced Micro Devices, Inc.
388dfc9a3SLikun Gao  * Copyright 2008 Red Hat Inc.
488dfc9a3SLikun Gao  * Copyright 2009 Jerome Glisse.
588dfc9a3SLikun Gao  *
688dfc9a3SLikun Gao  * Permission is hereby granted, free of charge, to any person obtaining a
788dfc9a3SLikun Gao  * copy of this software and associated documentation files (the "Software"),
888dfc9a3SLikun Gao  * to deal in the Software without restriction, including without limitation
988dfc9a3SLikun Gao  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1088dfc9a3SLikun Gao  * and/or sell copies of the Software, and to permit persons to whom the
1188dfc9a3SLikun Gao  * Software is furnished to do so, subject to the following conditions:
1288dfc9a3SLikun Gao  *
1388dfc9a3SLikun Gao  * The above copyright notice and this permission notice shall be included in
1488dfc9a3SLikun Gao  * all copies or substantial portions of the Software.
1588dfc9a3SLikun Gao  *
1688dfc9a3SLikun Gao  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1788dfc9a3SLikun Gao  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1888dfc9a3SLikun Gao  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1988dfc9a3SLikun Gao  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
2088dfc9a3SLikun Gao  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2188dfc9a3SLikun Gao  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2288dfc9a3SLikun Gao  * OTHER DEALINGS IN THE SOFTWARE.
2388dfc9a3SLikun Gao  *
2488dfc9a3SLikun Gao  */
25*106c7d61SLikun Gao #include <linux/firmware.h>
2688dfc9a3SLikun Gao #include "amdgpu.h"
2788dfc9a3SLikun Gao #include "amdgpu_gfx.h"
2888dfc9a3SLikun Gao #include "amdgpu_rlc.h"
2988dfc9a3SLikun Gao 
3088dfc9a3SLikun Gao /**
31*106c7d61SLikun Gao  * amdgpu_gfx_rlc_enter_safe_mode - Set RLC into safe mode
32*106c7d61SLikun Gao  *
33*106c7d61SLikun Gao  * @adev: amdgpu_device pointer
34*106c7d61SLikun Gao  *
35*106c7d61SLikun Gao  * Set RLC enter into safe mode if RLC is enabled and haven't in safe mode.
36*106c7d61SLikun Gao  */
37*106c7d61SLikun Gao void amdgpu_gfx_rlc_enter_safe_mode(struct amdgpu_device *adev)
38*106c7d61SLikun Gao {
39*106c7d61SLikun Gao 	if (adev->gfx.rlc.in_safe_mode)
40*106c7d61SLikun Gao 		return;
41*106c7d61SLikun Gao 
42*106c7d61SLikun Gao 	/* if RLC is not enabled, do nothing */
43*106c7d61SLikun Gao 	if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev))
44*106c7d61SLikun Gao 		return;
45*106c7d61SLikun Gao 
46*106c7d61SLikun Gao 	if (adev->cg_flags &
47*106c7d61SLikun Gao 	    (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG |
48*106c7d61SLikun Gao 	     AMD_CG_SUPPORT_GFX_3D_CGCG)) {
49*106c7d61SLikun Gao 		adev->gfx.rlc.funcs->set_safe_mode(adev);
50*106c7d61SLikun Gao 		adev->gfx.rlc.in_safe_mode = true;
51*106c7d61SLikun Gao 	}
52*106c7d61SLikun Gao }
53*106c7d61SLikun Gao 
54*106c7d61SLikun Gao /**
55*106c7d61SLikun Gao  * amdgpu_gfx_rlc_exit_safe_mode - Set RLC out of safe mode
56*106c7d61SLikun Gao  *
57*106c7d61SLikun Gao  * @adev: amdgpu_device pointer
58*106c7d61SLikun Gao  *
59*106c7d61SLikun Gao  * Set RLC exit safe mode if RLC is enabled and have entered into safe mode.
60*106c7d61SLikun Gao  */
61*106c7d61SLikun Gao void amdgpu_gfx_rlc_exit_safe_mode(struct amdgpu_device *adev)
62*106c7d61SLikun Gao {
63*106c7d61SLikun Gao 	if (!(adev->gfx.rlc.in_safe_mode))
64*106c7d61SLikun Gao 		return;
65*106c7d61SLikun Gao 
66*106c7d61SLikun Gao 	/* if RLC is not enabled, do nothing */
67*106c7d61SLikun Gao 	if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev))
68*106c7d61SLikun Gao 		return;
69*106c7d61SLikun Gao 
70*106c7d61SLikun Gao 	if (adev->cg_flags &
71*106c7d61SLikun Gao 	    (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG |
72*106c7d61SLikun Gao 	     AMD_CG_SUPPORT_GFX_3D_CGCG)) {
73*106c7d61SLikun Gao 		adev->gfx.rlc.funcs->unset_safe_mode(adev);
74*106c7d61SLikun Gao 		adev->gfx.rlc.in_safe_mode = false;
75*106c7d61SLikun Gao 	}
76*106c7d61SLikun Gao }
77*106c7d61SLikun Gao 
78*106c7d61SLikun Gao /**
79*106c7d61SLikun Gao  * amdgpu_gfx_rlc_init_sr - Init save restore block
80*106c7d61SLikun Gao  *
81*106c7d61SLikun Gao  * @adev: amdgpu_device pointer
82*106c7d61SLikun Gao  * @dws: the size of save restore block
83*106c7d61SLikun Gao  *
84*106c7d61SLikun Gao  * Allocate and setup value to save restore block of rlc.
85*106c7d61SLikun Gao  * Returns 0 on succeess or negative error code if allocate failed.
86*106c7d61SLikun Gao  */
87*106c7d61SLikun Gao int amdgpu_gfx_rlc_init_sr(struct amdgpu_device *adev, u32 dws)
88*106c7d61SLikun Gao {
89*106c7d61SLikun Gao 	const u32 *src_ptr;
90*106c7d61SLikun Gao 	volatile u32 *dst_ptr;
91*106c7d61SLikun Gao 	u32 i;
92*106c7d61SLikun Gao 	int r;
93*106c7d61SLikun Gao 
94*106c7d61SLikun Gao 	/* allocate save restore block */
95*106c7d61SLikun Gao 	r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
96*106c7d61SLikun Gao 				      AMDGPU_GEM_DOMAIN_VRAM,
97*106c7d61SLikun Gao 				      &adev->gfx.rlc.save_restore_obj,
98*106c7d61SLikun Gao 				      &adev->gfx.rlc.save_restore_gpu_addr,
99*106c7d61SLikun Gao 				      (void **)&adev->gfx.rlc.sr_ptr);
100*106c7d61SLikun Gao 	if (r) {
101*106c7d61SLikun Gao 		dev_warn(adev->dev, "(%d) create RLC sr bo failed\n", r);
102*106c7d61SLikun Gao 		amdgpu_gfx_rlc_fini(adev);
103*106c7d61SLikun Gao 		return r;
104*106c7d61SLikun Gao 	}
105*106c7d61SLikun Gao 
106*106c7d61SLikun Gao 	/* write the sr buffer */
107*106c7d61SLikun Gao 	src_ptr = adev->gfx.rlc.reg_list;
108*106c7d61SLikun Gao 	dst_ptr = adev->gfx.rlc.sr_ptr;
109*106c7d61SLikun Gao 	for (i = 0; i < adev->gfx.rlc.reg_list_size; i++)
110*106c7d61SLikun Gao 		dst_ptr[i] = cpu_to_le32(src_ptr[i]);
111*106c7d61SLikun Gao 	amdgpu_bo_kunmap(adev->gfx.rlc.save_restore_obj);
112*106c7d61SLikun Gao 	amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj);
113*106c7d61SLikun Gao 
114*106c7d61SLikun Gao 	return 0;
115*106c7d61SLikun Gao }
116*106c7d61SLikun Gao 
117*106c7d61SLikun Gao /**
118*106c7d61SLikun Gao  * amdgpu_gfx_rlc_init_csb - Init clear state block
119*106c7d61SLikun Gao  *
120*106c7d61SLikun Gao  * @adev: amdgpu_device pointer
121*106c7d61SLikun Gao  *
122*106c7d61SLikun Gao  * Allocate and setup value to clear state block of rlc.
123*106c7d61SLikun Gao  * Returns 0 on succeess or negative error code if allocate failed.
124*106c7d61SLikun Gao  */
125*106c7d61SLikun Gao int amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev)
126*106c7d61SLikun Gao {
127*106c7d61SLikun Gao 	volatile u32 *dst_ptr;
128*106c7d61SLikun Gao 	u32 dws;
129*106c7d61SLikun Gao 	int r;
130*106c7d61SLikun Gao 
131*106c7d61SLikun Gao 	/* allocate clear state block */
132*106c7d61SLikun Gao 	adev->gfx.rlc.clear_state_size = dws = adev->gfx.rlc.funcs->get_csb_size(adev);
133*106c7d61SLikun Gao 	r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
134*106c7d61SLikun Gao 				      AMDGPU_GEM_DOMAIN_VRAM,
135*106c7d61SLikun Gao 				      &adev->gfx.rlc.clear_state_obj,
136*106c7d61SLikun Gao 				      &adev->gfx.rlc.clear_state_gpu_addr,
137*106c7d61SLikun Gao 				      (void **)&adev->gfx.rlc.cs_ptr);
138*106c7d61SLikun Gao 	if (r) {
139*106c7d61SLikun Gao 		dev_err(adev->dev, "(%d) failed to create rlc csb bo\n", r);
140*106c7d61SLikun Gao 		amdgpu_gfx_rlc_fini(adev);
141*106c7d61SLikun Gao 		return r;
142*106c7d61SLikun Gao 	}
143*106c7d61SLikun Gao 
144*106c7d61SLikun Gao 	/* set up the cs buffer */
145*106c7d61SLikun Gao 	dst_ptr = adev->gfx.rlc.cs_ptr;
146*106c7d61SLikun Gao 	adev->gfx.rlc.funcs->get_csb_buffer(adev, dst_ptr);
147*106c7d61SLikun Gao 	amdgpu_bo_kunmap(adev->gfx.rlc.clear_state_obj);
148*106c7d61SLikun Gao 	amdgpu_bo_unpin(adev->gfx.rlc.clear_state_obj);
149*106c7d61SLikun Gao 	amdgpu_bo_unreserve(adev->gfx.rlc.clear_state_obj);
150*106c7d61SLikun Gao 
151*106c7d61SLikun Gao 	return 0;
152*106c7d61SLikun Gao }
153*106c7d61SLikun Gao 
154*106c7d61SLikun Gao /**
155*106c7d61SLikun Gao  * amdgpu_gfx_rlc_init_cpt - Init cp table
156*106c7d61SLikun Gao  *
157*106c7d61SLikun Gao  * @adev: amdgpu_device pointer
158*106c7d61SLikun Gao  *
159*106c7d61SLikun Gao  * Allocate and setup value to cp table of rlc.
160*106c7d61SLikun Gao  * Returns 0 on succeess or negative error code if allocate failed.
161*106c7d61SLikun Gao  */
162*106c7d61SLikun Gao int amdgpu_gfx_rlc_init_cpt(struct amdgpu_device *adev)
163*106c7d61SLikun Gao {
164*106c7d61SLikun Gao 	int r;
165*106c7d61SLikun Gao 
166*106c7d61SLikun Gao 	r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size,
167*106c7d61SLikun Gao 				      PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
168*106c7d61SLikun Gao 				      &adev->gfx.rlc.cp_table_obj,
169*106c7d61SLikun Gao 				      &adev->gfx.rlc.cp_table_gpu_addr,
170*106c7d61SLikun Gao 				      (void **)&adev->gfx.rlc.cp_table_ptr);
171*106c7d61SLikun Gao 	if (r) {
172*106c7d61SLikun Gao 		dev_err(adev->dev, "(%d) failed to create cp table bo\n", r);
173*106c7d61SLikun Gao 		amdgpu_gfx_rlc_fini(adev);
174*106c7d61SLikun Gao 		return r;
175*106c7d61SLikun Gao 	}
176*106c7d61SLikun Gao 
177*106c7d61SLikun Gao 	/* set up the cp table */
178*106c7d61SLikun Gao 	amdgpu_gfx_rlc_setup_cp_table(adev);
179*106c7d61SLikun Gao 	amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj);
180*106c7d61SLikun Gao 	amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
181*106c7d61SLikun Gao 
182*106c7d61SLikun Gao 	return 0;
183*106c7d61SLikun Gao }
184*106c7d61SLikun Gao 
185*106c7d61SLikun Gao /**
186*106c7d61SLikun Gao  * amdgpu_gfx_rlc_setup_cp_table - setup cp the buffer of cp table
187*106c7d61SLikun Gao  *
188*106c7d61SLikun Gao  * @adev: amdgpu_device pointer
189*106c7d61SLikun Gao  *
190*106c7d61SLikun Gao  * Write cp firmware data into cp table.
191*106c7d61SLikun Gao  */
192*106c7d61SLikun Gao void amdgpu_gfx_rlc_setup_cp_table(struct amdgpu_device *adev)
193*106c7d61SLikun Gao {
194*106c7d61SLikun Gao 	const __le32 *fw_data;
195*106c7d61SLikun Gao 	volatile u32 *dst_ptr;
196*106c7d61SLikun Gao 	int me, i, max_me;
197*106c7d61SLikun Gao 	u32 bo_offset = 0;
198*106c7d61SLikun Gao 	u32 table_offset, table_size;
199*106c7d61SLikun Gao 
200*106c7d61SLikun Gao 	max_me = adev->gfx.rlc.funcs->get_cp_table_num(adev);
201*106c7d61SLikun Gao 
202*106c7d61SLikun Gao 	/* write the cp table buffer */
203*106c7d61SLikun Gao 	dst_ptr = adev->gfx.rlc.cp_table_ptr;
204*106c7d61SLikun Gao 	for (me = 0; me < max_me; me++) {
205*106c7d61SLikun Gao 		if (me == 0) {
206*106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
207*106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
208*106c7d61SLikun Gao 			fw_data = (const __le32 *)
209*106c7d61SLikun Gao 				(adev->gfx.ce_fw->data +
210*106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
211*106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
212*106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
213*106c7d61SLikun Gao 		} else if (me == 1) {
214*106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
215*106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
216*106c7d61SLikun Gao 			fw_data = (const __le32 *)
217*106c7d61SLikun Gao 				(adev->gfx.pfp_fw->data +
218*106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
219*106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
220*106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
221*106c7d61SLikun Gao 		} else if (me == 2) {
222*106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
223*106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
224*106c7d61SLikun Gao 			fw_data = (const __le32 *)
225*106c7d61SLikun Gao 				(adev->gfx.me_fw->data +
226*106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
227*106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
228*106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
229*106c7d61SLikun Gao 		} else if (me == 3) {
230*106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
231*106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
232*106c7d61SLikun Gao 			fw_data = (const __le32 *)
233*106c7d61SLikun Gao 				(adev->gfx.mec_fw->data +
234*106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
235*106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
236*106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
237*106c7d61SLikun Gao 		} else  if (me == 4) {
238*106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
239*106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
240*106c7d61SLikun Gao 			fw_data = (const __le32 *)
241*106c7d61SLikun Gao 				(adev->gfx.mec2_fw->data +
242*106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
243*106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
244*106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
245*106c7d61SLikun Gao 		}
246*106c7d61SLikun Gao 
247*106c7d61SLikun Gao 		for (i = 0; i < table_size; i ++) {
248*106c7d61SLikun Gao 			dst_ptr[bo_offset + i] =
249*106c7d61SLikun Gao 				cpu_to_le32(le32_to_cpu(fw_data[table_offset + i]));
250*106c7d61SLikun Gao 		}
251*106c7d61SLikun Gao 
252*106c7d61SLikun Gao 		bo_offset += table_size;
253*106c7d61SLikun Gao 	}
254*106c7d61SLikun Gao }
255*106c7d61SLikun Gao 
256*106c7d61SLikun Gao /**
25788dfc9a3SLikun Gao  * amdgpu_gfx_rlc_fini - Free BO which used for RLC
25888dfc9a3SLikun Gao  *
25988dfc9a3SLikun Gao  * @adev: amdgpu_device pointer
26088dfc9a3SLikun Gao  *
26188dfc9a3SLikun Gao  * Free three BO which is used for rlc_save_restore_block, rlc_clear_state_block
26288dfc9a3SLikun Gao  * and rlc_jump_table_block.
26388dfc9a3SLikun Gao  */
26488dfc9a3SLikun Gao void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev)
26588dfc9a3SLikun Gao {
26688dfc9a3SLikun Gao 	/* save restore block */
26788dfc9a3SLikun Gao 	if (adev->gfx.rlc.save_restore_obj) {
26888dfc9a3SLikun Gao 		amdgpu_bo_free_kernel(&adev->gfx.rlc.save_restore_obj,
26988dfc9a3SLikun Gao 				      &adev->gfx.rlc.save_restore_gpu_addr,
27088dfc9a3SLikun Gao 				      (void **)&adev->gfx.rlc.sr_ptr);
27188dfc9a3SLikun Gao 	}
27288dfc9a3SLikun Gao 
27388dfc9a3SLikun Gao 	/* clear state block */
27488dfc9a3SLikun Gao 	amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
27588dfc9a3SLikun Gao 			      &adev->gfx.rlc.clear_state_gpu_addr,
27688dfc9a3SLikun Gao 			      (void **)&adev->gfx.rlc.cs_ptr);
27788dfc9a3SLikun Gao 
27888dfc9a3SLikun Gao 	/* jump table block */
27988dfc9a3SLikun Gao 	amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj,
28088dfc9a3SLikun Gao 			      &adev->gfx.rlc.cp_table_gpu_addr,
28188dfc9a3SLikun Gao 			      (void **)&adev->gfx.rlc.cp_table_ptr);
28288dfc9a3SLikun Gao }
283