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  */
25106c7d61SLikun 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 /**
31106c7d61SLikun Gao  * amdgpu_gfx_rlc_enter_safe_mode - Set RLC into safe mode
32106c7d61SLikun Gao  *
33106c7d61SLikun Gao  * @adev: amdgpu_device pointer
34106c7d61SLikun Gao  *
35106c7d61SLikun Gao  * Set RLC enter into safe mode if RLC is enabled and haven't in safe mode.
36106c7d61SLikun Gao  */
37106c7d61SLikun Gao void amdgpu_gfx_rlc_enter_safe_mode(struct amdgpu_device *adev)
38106c7d61SLikun Gao {
39106c7d61SLikun Gao 	if (adev->gfx.rlc.in_safe_mode)
40106c7d61SLikun Gao 		return;
41106c7d61SLikun Gao 
42106c7d61SLikun Gao 	/* if RLC is not enabled, do nothing */
43106c7d61SLikun Gao 	if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev))
44106c7d61SLikun Gao 		return;
45106c7d61SLikun Gao 
46106c7d61SLikun Gao 	if (adev->cg_flags &
47106c7d61SLikun Gao 	    (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG |
48106c7d61SLikun Gao 	     AMD_CG_SUPPORT_GFX_3D_CGCG)) {
49106c7d61SLikun Gao 		adev->gfx.rlc.funcs->set_safe_mode(adev);
50106c7d61SLikun Gao 		adev->gfx.rlc.in_safe_mode = true;
51106c7d61SLikun Gao 	}
52106c7d61SLikun Gao }
53106c7d61SLikun Gao 
54106c7d61SLikun Gao /**
55106c7d61SLikun Gao  * amdgpu_gfx_rlc_exit_safe_mode - Set RLC out of safe mode
56106c7d61SLikun Gao  *
57106c7d61SLikun Gao  * @adev: amdgpu_device pointer
58106c7d61SLikun Gao  *
59106c7d61SLikun Gao  * Set RLC exit safe mode if RLC is enabled and have entered into safe mode.
60106c7d61SLikun Gao  */
61106c7d61SLikun Gao void amdgpu_gfx_rlc_exit_safe_mode(struct amdgpu_device *adev)
62106c7d61SLikun Gao {
63106c7d61SLikun Gao 	if (!(adev->gfx.rlc.in_safe_mode))
64106c7d61SLikun Gao 		return;
65106c7d61SLikun Gao 
66106c7d61SLikun Gao 	/* if RLC is not enabled, do nothing */
67106c7d61SLikun Gao 	if (!adev->gfx.rlc.funcs->is_rlc_enabled(adev))
68106c7d61SLikun Gao 		return;
69106c7d61SLikun Gao 
70106c7d61SLikun Gao 	if (adev->cg_flags &
71106c7d61SLikun Gao 	    (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_MGCG |
72106c7d61SLikun Gao 	     AMD_CG_SUPPORT_GFX_3D_CGCG)) {
73106c7d61SLikun Gao 		adev->gfx.rlc.funcs->unset_safe_mode(adev);
74106c7d61SLikun Gao 		adev->gfx.rlc.in_safe_mode = false;
75106c7d61SLikun Gao 	}
76106c7d61SLikun Gao }
77106c7d61SLikun Gao 
78106c7d61SLikun Gao /**
79106c7d61SLikun Gao  * amdgpu_gfx_rlc_init_sr - Init save restore block
80106c7d61SLikun Gao  *
81106c7d61SLikun Gao  * @adev: amdgpu_device pointer
82106c7d61SLikun Gao  * @dws: the size of save restore block
83106c7d61SLikun Gao  *
84106c7d61SLikun Gao  * Allocate and setup value to save restore block of rlc.
85106c7d61SLikun Gao  * Returns 0 on succeess or negative error code if allocate failed.
86106c7d61SLikun Gao  */
87106c7d61SLikun Gao int amdgpu_gfx_rlc_init_sr(struct amdgpu_device *adev, u32 dws)
88106c7d61SLikun Gao {
89106c7d61SLikun Gao 	const u32 *src_ptr;
90106c7d61SLikun Gao 	volatile u32 *dst_ptr;
91106c7d61SLikun Gao 	u32 i;
92106c7d61SLikun Gao 	int r;
93106c7d61SLikun Gao 
94106c7d61SLikun Gao 	/* allocate save restore block */
95106c7d61SLikun Gao 	r = amdgpu_bo_create_reserved(adev, dws * 4, PAGE_SIZE,
96106c7d61SLikun Gao 				      AMDGPU_GEM_DOMAIN_VRAM,
97106c7d61SLikun Gao 				      &adev->gfx.rlc.save_restore_obj,
98106c7d61SLikun Gao 				      &adev->gfx.rlc.save_restore_gpu_addr,
99106c7d61SLikun Gao 				      (void **)&adev->gfx.rlc.sr_ptr);
100106c7d61SLikun Gao 	if (r) {
101106c7d61SLikun Gao 		dev_warn(adev->dev, "(%d) create RLC sr bo failed\n", r);
102106c7d61SLikun Gao 		amdgpu_gfx_rlc_fini(adev);
103106c7d61SLikun Gao 		return r;
104106c7d61SLikun Gao 	}
105106c7d61SLikun Gao 
106106c7d61SLikun Gao 	/* write the sr buffer */
107106c7d61SLikun Gao 	src_ptr = adev->gfx.rlc.reg_list;
108106c7d61SLikun Gao 	dst_ptr = adev->gfx.rlc.sr_ptr;
109106c7d61SLikun Gao 	for (i = 0; i < adev->gfx.rlc.reg_list_size; i++)
110106c7d61SLikun Gao 		dst_ptr[i] = cpu_to_le32(src_ptr[i]);
111106c7d61SLikun Gao 	amdgpu_bo_kunmap(adev->gfx.rlc.save_restore_obj);
112106c7d61SLikun Gao 	amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj);
113106c7d61SLikun Gao 
114106c7d61SLikun Gao 	return 0;
115106c7d61SLikun Gao }
116106c7d61SLikun Gao 
117106c7d61SLikun Gao /**
118106c7d61SLikun Gao  * amdgpu_gfx_rlc_init_csb - Init clear state block
119106c7d61SLikun Gao  *
120106c7d61SLikun Gao  * @adev: amdgpu_device pointer
121106c7d61SLikun Gao  *
122106c7d61SLikun Gao  * Allocate and setup value to clear state block of rlc.
123106c7d61SLikun Gao  * Returns 0 on succeess or negative error code if allocate failed.
124106c7d61SLikun Gao  */
125106c7d61SLikun Gao int amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev)
126106c7d61SLikun Gao {
127106c7d61SLikun Gao 	u32 dws;
128106c7d61SLikun Gao 	int r;
129106c7d61SLikun Gao 
130106c7d61SLikun Gao 	/* allocate clear state block */
131106c7d61SLikun Gao 	adev->gfx.rlc.clear_state_size = dws = adev->gfx.rlc.funcs->get_csb_size(adev);
132*747d4f71SMonk Liu 	r = amdgpu_bo_create_kernel(adev, dws * 4, PAGE_SIZE,
133106c7d61SLikun Gao 				      AMDGPU_GEM_DOMAIN_VRAM,
134106c7d61SLikun Gao 				      &adev->gfx.rlc.clear_state_obj,
135106c7d61SLikun Gao 				      &adev->gfx.rlc.clear_state_gpu_addr,
136106c7d61SLikun Gao 				      (void **)&adev->gfx.rlc.cs_ptr);
137106c7d61SLikun Gao 	if (r) {
138106c7d61SLikun Gao 		dev_err(adev->dev, "(%d) failed to create rlc csb bo\n", r);
139106c7d61SLikun Gao 		amdgpu_gfx_rlc_fini(adev);
140106c7d61SLikun Gao 		return r;
141106c7d61SLikun Gao 	}
142106c7d61SLikun Gao 
143106c7d61SLikun Gao 	return 0;
144106c7d61SLikun Gao }
145106c7d61SLikun Gao 
146106c7d61SLikun Gao /**
147106c7d61SLikun Gao  * amdgpu_gfx_rlc_init_cpt - Init cp table
148106c7d61SLikun Gao  *
149106c7d61SLikun Gao  * @adev: amdgpu_device pointer
150106c7d61SLikun Gao  *
151106c7d61SLikun Gao  * Allocate and setup value to cp table of rlc.
152106c7d61SLikun Gao  * Returns 0 on succeess or negative error code if allocate failed.
153106c7d61SLikun Gao  */
154106c7d61SLikun Gao int amdgpu_gfx_rlc_init_cpt(struct amdgpu_device *adev)
155106c7d61SLikun Gao {
156106c7d61SLikun Gao 	int r;
157106c7d61SLikun Gao 
158106c7d61SLikun Gao 	r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size,
159106c7d61SLikun Gao 				      PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
160106c7d61SLikun Gao 				      &adev->gfx.rlc.cp_table_obj,
161106c7d61SLikun Gao 				      &adev->gfx.rlc.cp_table_gpu_addr,
162106c7d61SLikun Gao 				      (void **)&adev->gfx.rlc.cp_table_ptr);
163106c7d61SLikun Gao 	if (r) {
164106c7d61SLikun Gao 		dev_err(adev->dev, "(%d) failed to create cp table bo\n", r);
165106c7d61SLikun Gao 		amdgpu_gfx_rlc_fini(adev);
166106c7d61SLikun Gao 		return r;
167106c7d61SLikun Gao 	}
168106c7d61SLikun Gao 
169106c7d61SLikun Gao 	/* set up the cp table */
170106c7d61SLikun Gao 	amdgpu_gfx_rlc_setup_cp_table(adev);
171106c7d61SLikun Gao 	amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj);
172106c7d61SLikun Gao 	amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
173106c7d61SLikun Gao 
174106c7d61SLikun Gao 	return 0;
175106c7d61SLikun Gao }
176106c7d61SLikun Gao 
177106c7d61SLikun Gao /**
178106c7d61SLikun Gao  * amdgpu_gfx_rlc_setup_cp_table - setup cp the buffer of cp table
179106c7d61SLikun Gao  *
180106c7d61SLikun Gao  * @adev: amdgpu_device pointer
181106c7d61SLikun Gao  *
182106c7d61SLikun Gao  * Write cp firmware data into cp table.
183106c7d61SLikun Gao  */
184106c7d61SLikun Gao void amdgpu_gfx_rlc_setup_cp_table(struct amdgpu_device *adev)
185106c7d61SLikun Gao {
186106c7d61SLikun Gao 	const __le32 *fw_data;
187106c7d61SLikun Gao 	volatile u32 *dst_ptr;
188106c7d61SLikun Gao 	int me, i, max_me;
189106c7d61SLikun Gao 	u32 bo_offset = 0;
190106c7d61SLikun Gao 	u32 table_offset, table_size;
191106c7d61SLikun Gao 
192106c7d61SLikun Gao 	max_me = adev->gfx.rlc.funcs->get_cp_table_num(adev);
193106c7d61SLikun Gao 
194106c7d61SLikun Gao 	/* write the cp table buffer */
195106c7d61SLikun Gao 	dst_ptr = adev->gfx.rlc.cp_table_ptr;
196106c7d61SLikun Gao 	for (me = 0; me < max_me; me++) {
197106c7d61SLikun Gao 		if (me == 0) {
198106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
199106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
200106c7d61SLikun Gao 			fw_data = (const __le32 *)
201106c7d61SLikun Gao 				(adev->gfx.ce_fw->data +
202106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
203106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
204106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
205106c7d61SLikun Gao 		} else if (me == 1) {
206106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
207106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
208106c7d61SLikun Gao 			fw_data = (const __le32 *)
209106c7d61SLikun Gao 				(adev->gfx.pfp_fw->data +
210106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
211106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
212106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
213106c7d61SLikun Gao 		} else if (me == 2) {
214106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
215106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
216106c7d61SLikun Gao 			fw_data = (const __le32 *)
217106c7d61SLikun Gao 				(adev->gfx.me_fw->data +
218106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
219106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
220106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
221106c7d61SLikun Gao 		} else if (me == 3) {
222106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
223106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
224106c7d61SLikun Gao 			fw_data = (const __le32 *)
225106c7d61SLikun Gao 				(adev->gfx.mec_fw->data +
226106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
227106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
228106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
229106c7d61SLikun Gao 		} else  if (me == 4) {
230106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
231106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
232106c7d61SLikun Gao 			fw_data = (const __le32 *)
233106c7d61SLikun Gao 				(adev->gfx.mec2_fw->data +
234106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
235106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
236106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
237106c7d61SLikun Gao 		}
238106c7d61SLikun Gao 
239106c7d61SLikun Gao 		for (i = 0; i < table_size; i ++) {
240106c7d61SLikun Gao 			dst_ptr[bo_offset + i] =
241106c7d61SLikun Gao 				cpu_to_le32(le32_to_cpu(fw_data[table_offset + i]));
242106c7d61SLikun Gao 		}
243106c7d61SLikun Gao 
244106c7d61SLikun Gao 		bo_offset += table_size;
245106c7d61SLikun Gao 	}
246106c7d61SLikun Gao }
247106c7d61SLikun Gao 
248106c7d61SLikun Gao /**
24988dfc9a3SLikun Gao  * amdgpu_gfx_rlc_fini - Free BO which used for RLC
25088dfc9a3SLikun Gao  *
25188dfc9a3SLikun Gao  * @adev: amdgpu_device pointer
25288dfc9a3SLikun Gao  *
25388dfc9a3SLikun Gao  * Free three BO which is used for rlc_save_restore_block, rlc_clear_state_block
25488dfc9a3SLikun Gao  * and rlc_jump_table_block.
25588dfc9a3SLikun Gao  */
25688dfc9a3SLikun Gao void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev)
25788dfc9a3SLikun Gao {
25888dfc9a3SLikun Gao 	/* save restore block */
25988dfc9a3SLikun Gao 	if (adev->gfx.rlc.save_restore_obj) {
26088dfc9a3SLikun Gao 		amdgpu_bo_free_kernel(&adev->gfx.rlc.save_restore_obj,
26188dfc9a3SLikun Gao 				      &adev->gfx.rlc.save_restore_gpu_addr,
26288dfc9a3SLikun Gao 				      (void **)&adev->gfx.rlc.sr_ptr);
26388dfc9a3SLikun Gao 	}
26488dfc9a3SLikun Gao 
26588dfc9a3SLikun Gao 	/* clear state block */
26688dfc9a3SLikun Gao 	amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
26788dfc9a3SLikun Gao 			      &adev->gfx.rlc.clear_state_gpu_addr,
26888dfc9a3SLikun Gao 			      (void **)&adev->gfx.rlc.cs_ptr);
26988dfc9a3SLikun Gao 
27088dfc9a3SLikun Gao 	/* jump table block */
27188dfc9a3SLikun Gao 	amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj,
27288dfc9a3SLikun Gao 			      &adev->gfx.rlc.cp_table_gpu_addr,
27388dfc9a3SLikun Gao 			      (void **)&adev->gfx.rlc.cp_table_ptr);
27488dfc9a3SLikun Gao }
275