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);
132747d4f71SMonk 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 }
2750641dbefSHawking Zhang 
2760641dbefSHawking Zhang static int amdgpu_gfx_rlc_init_microcode_v2_0(struct amdgpu_device *adev)
2770641dbefSHawking Zhang {
2780641dbefSHawking Zhang 	const struct common_firmware_header *common_hdr;
2790641dbefSHawking Zhang 	const struct rlc_firmware_header_v2_0 *rlc_hdr;
2800641dbefSHawking Zhang 	struct amdgpu_firmware_info *info;
2810641dbefSHawking Zhang 	unsigned int *tmp;
2820641dbefSHawking Zhang 	unsigned int i;
2830641dbefSHawking Zhang 
2840641dbefSHawking Zhang 	rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data;
2850641dbefSHawking Zhang 
2860641dbefSHawking Zhang 	adev->gfx.rlc_fw_version = le32_to_cpu(rlc_hdr->header.ucode_version);
2870641dbefSHawking Zhang 	adev->gfx.rlc_feature_version = le32_to_cpu(rlc_hdr->ucode_feature_version);
2880641dbefSHawking Zhang 	adev->gfx.rlc.save_and_restore_offset =
2890641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->save_and_restore_offset);
2900641dbefSHawking Zhang 	adev->gfx.rlc.clear_state_descriptor_offset =
2910641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->clear_state_descriptor_offset);
2920641dbefSHawking Zhang 	adev->gfx.rlc.avail_scratch_ram_locations =
2930641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->avail_scratch_ram_locations);
2940641dbefSHawking Zhang 	adev->gfx.rlc.reg_restore_list_size =
2950641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->reg_restore_list_size);
2960641dbefSHawking Zhang 	adev->gfx.rlc.reg_list_format_start =
2970641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->reg_list_format_start);
2980641dbefSHawking Zhang 	adev->gfx.rlc.reg_list_format_separate_start =
2990641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->reg_list_format_separate_start);
3000641dbefSHawking Zhang 	adev->gfx.rlc.starting_offsets_start =
3010641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->starting_offsets_start);
3020641dbefSHawking Zhang 	adev->gfx.rlc.reg_list_format_size_bytes =
3030641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->reg_list_format_size_bytes);
3040641dbefSHawking Zhang 	adev->gfx.rlc.reg_list_size_bytes =
3050641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->reg_list_size_bytes);
3060641dbefSHawking Zhang 	adev->gfx.rlc.register_list_format =
3070641dbefSHawking Zhang 		kmalloc(adev->gfx.rlc.reg_list_format_size_bytes +
3080641dbefSHawking Zhang 			adev->gfx.rlc.reg_list_size_bytes, GFP_KERNEL);
3090641dbefSHawking Zhang 	if (!adev->gfx.rlc.register_list_format) {
3100641dbefSHawking Zhang 		dev_err(adev->dev, "failed to allocate memory for rlc register_list_format\n");
3110641dbefSHawking Zhang 		return -ENOMEM;
3120641dbefSHawking Zhang 	}
3130641dbefSHawking Zhang 
3140641dbefSHawking Zhang 	tmp = (unsigned int *)((uintptr_t)rlc_hdr +
3150641dbefSHawking Zhang 			le32_to_cpu(rlc_hdr->reg_list_format_array_offset_bytes));
3160641dbefSHawking Zhang 	for (i = 0 ; i < (rlc_hdr->reg_list_format_size_bytes >> 2); i++)
3170641dbefSHawking Zhang 		adev->gfx.rlc.register_list_format[i] = le32_to_cpu(tmp[i]);
3180641dbefSHawking Zhang 
3190641dbefSHawking Zhang 	adev->gfx.rlc.register_restore = adev->gfx.rlc.register_list_format + i;
3200641dbefSHawking Zhang 
3210641dbefSHawking Zhang 	tmp = (unsigned int *)((uintptr_t)rlc_hdr +
3220641dbefSHawking Zhang 			le32_to_cpu(rlc_hdr->reg_list_array_offset_bytes));
3230641dbefSHawking Zhang 	for (i = 0 ; i < (rlc_hdr->reg_list_size_bytes >> 2); i++)
3240641dbefSHawking Zhang 		adev->gfx.rlc.register_restore[i] = le32_to_cpu(tmp[i]);
3250641dbefSHawking Zhang 
3260641dbefSHawking Zhang 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
3270641dbefSHawking Zhang 		info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_G];
3280641dbefSHawking Zhang 		info->ucode_id = AMDGPU_UCODE_ID_RLC_G;
3290641dbefSHawking Zhang 		info->fw = adev->gfx.rlc_fw;
3300641dbefSHawking Zhang 		if (info->fw) {
3310641dbefSHawking Zhang 			common_hdr = (const struct common_firmware_header *)info->fw->data;
3320641dbefSHawking Zhang 			adev->firmware.fw_size +=
3330641dbefSHawking Zhang 				ALIGN(le32_to_cpu(common_hdr->ucode_size_bytes), PAGE_SIZE);
3340641dbefSHawking Zhang 		}
3350641dbefSHawking Zhang 	}
3360641dbefSHawking Zhang 
3370641dbefSHawking Zhang 	return 0;
3380641dbefSHawking Zhang }
339f3e6173bSHawking Zhang 
340f3e6173bSHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_1(struct amdgpu_device *adev)
341f3e6173bSHawking Zhang {
342f3e6173bSHawking Zhang 	const struct rlc_firmware_header_v2_1 *rlc_hdr;
343f3e6173bSHawking Zhang 	struct amdgpu_firmware_info *info;
344f3e6173bSHawking Zhang 
345f3e6173bSHawking Zhang 	rlc_hdr = (const struct rlc_firmware_header_v2_1 *)adev->gfx.rlc_fw->data;
346f3e6173bSHawking Zhang 	adev->gfx.rlc_srlc_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_ucode_ver);
347f3e6173bSHawking Zhang 	adev->gfx.rlc_srlc_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_feature_ver);
348f3e6173bSHawking Zhang 	adev->gfx.rlc.save_restore_list_cntl_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_cntl_size_bytes);
349f3e6173bSHawking Zhang 	adev->gfx.rlc.save_restore_list_cntl = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_cntl_offset_bytes);
350f3e6173bSHawking Zhang 	adev->gfx.rlc_srlg_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_ucode_ver);
351f3e6173bSHawking Zhang 	adev->gfx.rlc_srlg_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_feature_ver);
352f3e6173bSHawking Zhang 	adev->gfx.rlc.save_restore_list_gpm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_gpm_size_bytes);
353f3e6173bSHawking Zhang 	adev->gfx.rlc.save_restore_list_gpm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_gpm_offset_bytes);
354f3e6173bSHawking Zhang 	adev->gfx.rlc_srls_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_ucode_ver);
355f3e6173bSHawking Zhang 	adev->gfx.rlc_srls_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_feature_ver);
356f3e6173bSHawking Zhang 	adev->gfx.rlc.save_restore_list_srm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_srm_size_bytes);
357f3e6173bSHawking Zhang 	adev->gfx.rlc.save_restore_list_srm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_srm_offset_bytes);
358f3e6173bSHawking Zhang 	adev->gfx.rlc.reg_list_format_direct_reg_list_length =
359f3e6173bSHawking Zhang 		le32_to_cpu(rlc_hdr->reg_list_format_direct_reg_list_length);
360f3e6173bSHawking Zhang 
361f3e6173bSHawking Zhang 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
362f3e6173bSHawking Zhang 		if (adev->gfx.rlc.save_restore_list_gpm_size_bytes) {
363f3e6173bSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM];
364f3e6173bSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM;
365f3e6173bSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
366f3e6173bSHawking Zhang 			adev->firmware.fw_size +=
367f3e6173bSHawking Zhang 				ALIGN(adev->gfx.rlc.save_restore_list_gpm_size_bytes, PAGE_SIZE);
368f3e6173bSHawking Zhang 		}
369f3e6173bSHawking Zhang 
370f3e6173bSHawking Zhang 		if (adev->gfx.rlc.save_restore_list_srm_size_bytes) {
371f3e6173bSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM];
372f3e6173bSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM;
373f3e6173bSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
374f3e6173bSHawking Zhang 			adev->firmware.fw_size +=
375f3e6173bSHawking Zhang 				ALIGN(adev->gfx.rlc.save_restore_list_srm_size_bytes, PAGE_SIZE);
376f3e6173bSHawking Zhang 		}
377f3e6173bSHawking Zhang 	}
378f3e6173bSHawking Zhang }
379a97d0ec8SHawking Zhang 
380a97d0ec8SHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_2(struct amdgpu_device *adev)
381a97d0ec8SHawking Zhang {
382a97d0ec8SHawking Zhang 	const struct rlc_firmware_header_v2_2 *rlc_hdr;
383a97d0ec8SHawking Zhang 	struct amdgpu_firmware_info *info;
384a97d0ec8SHawking Zhang 
385a97d0ec8SHawking Zhang 	rlc_hdr = (const struct rlc_firmware_header_v2_2 *)adev->gfx.rlc_fw->data;
386a97d0ec8SHawking Zhang 	adev->gfx.rlc.rlc_iram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_iram_ucode_size_bytes);
387a97d0ec8SHawking Zhang 	adev->gfx.rlc.rlc_iram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_iram_ucode_offset_bytes);
388a97d0ec8SHawking Zhang 	adev->gfx.rlc.rlc_dram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_dram_ucode_size_bytes);
389a97d0ec8SHawking Zhang 	adev->gfx.rlc.rlc_dram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_dram_ucode_offset_bytes);
390a97d0ec8SHawking Zhang 
391a97d0ec8SHawking Zhang 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
392a97d0ec8SHawking Zhang 		if (adev->gfx.rlc.rlc_iram_ucode_size_bytes) {
393a97d0ec8SHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_IRAM];
394a97d0ec8SHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_RLC_IRAM;
395a97d0ec8SHawking Zhang 			info->fw = adev->gfx.rlc_fw;
396a97d0ec8SHawking Zhang 			adev->firmware.fw_size +=
397a97d0ec8SHawking Zhang 				ALIGN(adev->gfx.rlc.rlc_iram_ucode_size_bytes, PAGE_SIZE);
398a97d0ec8SHawking Zhang 		}
399a97d0ec8SHawking Zhang 
400a97d0ec8SHawking Zhang 		if (adev->gfx.rlc.rlc_dram_ucode_size_bytes) {
401a97d0ec8SHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_DRAM];
402a97d0ec8SHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_RLC_DRAM;
403a97d0ec8SHawking Zhang 			info->fw = adev->gfx.rlc_fw;
404a97d0ec8SHawking Zhang 			adev->firmware.fw_size +=
405a97d0ec8SHawking Zhang 				ALIGN(adev->gfx.rlc.rlc_dram_ucode_size_bytes, PAGE_SIZE);
406a97d0ec8SHawking Zhang 		}
407a97d0ec8SHawking Zhang 	}
408a97d0ec8SHawking Zhang }
409a0d9084dSHawking Zhang 
410a0d9084dSHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_3(struct amdgpu_device *adev)
411a0d9084dSHawking Zhang {
412a0d9084dSHawking Zhang 	const struct rlc_firmware_header_v2_3 *rlc_hdr;
413a0d9084dSHawking Zhang 	struct amdgpu_firmware_info *info;
414a0d9084dSHawking Zhang 
415a0d9084dSHawking Zhang 	rlc_hdr = (const struct rlc_firmware_header_v2_3 *)adev->gfx.rlc_fw->data;
416a0d9084dSHawking Zhang 	adev->gfx.rlcp_ucode_version = le32_to_cpu(rlc_hdr->rlcp_ucode_version);
417a0d9084dSHawking Zhang 	adev->gfx.rlcp_ucode_feature_version = le32_to_cpu(rlc_hdr->rlcp_ucode_feature_version);
418a0d9084dSHawking Zhang 	adev->gfx.rlc.rlcp_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlcp_ucode_size_bytes);
419a0d9084dSHawking Zhang 	adev->gfx.rlc.rlcp_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlcp_ucode_offset_bytes);
420a0d9084dSHawking Zhang 
421a0d9084dSHawking Zhang 	adev->gfx.rlcv_ucode_version = le32_to_cpu(rlc_hdr->rlcv_ucode_version);
422a0d9084dSHawking Zhang 	adev->gfx.rlcv_ucode_feature_version = le32_to_cpu(rlc_hdr->rlcv_ucode_feature_version);
423a0d9084dSHawking Zhang 	adev->gfx.rlc.rlcv_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlcv_ucode_size_bytes);
424a0d9084dSHawking Zhang 	adev->gfx.rlc.rlcv_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlcv_ucode_offset_bytes);
425a0d9084dSHawking Zhang 
426a0d9084dSHawking Zhang 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
427a0d9084dSHawking Zhang 		if (adev->gfx.rlc.rlcp_ucode_size_bytes) {
428a0d9084dSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_P];
429a0d9084dSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_RLC_P;
430a0d9084dSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
431a0d9084dSHawking Zhang 			adev->firmware.fw_size +=
432a0d9084dSHawking Zhang 				ALIGN(adev->gfx.rlc.rlcp_ucode_size_bytes, PAGE_SIZE);
433a0d9084dSHawking Zhang 		}
434a0d9084dSHawking Zhang 
435a0d9084dSHawking Zhang 		if (adev->gfx.rlc.rlcv_ucode_size_bytes) {
436a0d9084dSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_V];
437a0d9084dSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_RLC_V;
438a0d9084dSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
439a0d9084dSHawking Zhang 			adev->firmware.fw_size +=
440a0d9084dSHawking Zhang 				ALIGN(adev->gfx.rlc.rlcv_ucode_size_bytes, PAGE_SIZE);
441a0d9084dSHawking Zhang 		}
442a0d9084dSHawking Zhang 	}
443a0d9084dSHawking Zhang }
444435d6e6fSHawking Zhang 
445435d6e6fSHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_4(struct amdgpu_device *adev)
446435d6e6fSHawking Zhang {
447435d6e6fSHawking Zhang 	const struct rlc_firmware_header_v2_4 *rlc_hdr;
448435d6e6fSHawking Zhang 	struct amdgpu_firmware_info *info;
449435d6e6fSHawking Zhang 
450435d6e6fSHawking Zhang 	rlc_hdr = (const struct rlc_firmware_header_v2_4 *)adev->gfx.rlc_fw->data;
451435d6e6fSHawking Zhang 	adev->gfx.rlc.global_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->global_tap_delays_ucode_size_bytes);
452435d6e6fSHawking Zhang 	adev->gfx.rlc.global_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->global_tap_delays_ucode_offset_bytes);
453435d6e6fSHawking Zhang 	adev->gfx.rlc.se0_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se0_tap_delays_ucode_size_bytes);
454435d6e6fSHawking Zhang 	adev->gfx.rlc.se0_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se0_tap_delays_ucode_offset_bytes);
455435d6e6fSHawking Zhang 	adev->gfx.rlc.se1_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se1_tap_delays_ucode_size_bytes);
456435d6e6fSHawking Zhang 	adev->gfx.rlc.se1_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se1_tap_delays_ucode_offset_bytes);
457435d6e6fSHawking Zhang 	adev->gfx.rlc.se2_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se2_tap_delays_ucode_size_bytes);
458435d6e6fSHawking Zhang 	adev->gfx.rlc.se2_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se2_tap_delays_ucode_offset_bytes);
459435d6e6fSHawking Zhang 	adev->gfx.rlc.se3_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se3_tap_delays_ucode_size_bytes);
460435d6e6fSHawking Zhang 	adev->gfx.rlc.se3_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se3_tap_delays_ucode_offset_bytes);
461435d6e6fSHawking Zhang 
462435d6e6fSHawking Zhang 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
463435d6e6fSHawking Zhang 		if (adev->gfx.rlc.global_tap_delays_ucode_size_bytes) {
464435d6e6fSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS];
465435d6e6fSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS;
466435d6e6fSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
467435d6e6fSHawking Zhang 			adev->firmware.fw_size +=
468435d6e6fSHawking Zhang 				ALIGN(adev->gfx.rlc.global_tap_delays_ucode_size_bytes, PAGE_SIZE);
469435d6e6fSHawking Zhang 		}
470435d6e6fSHawking Zhang 
471435d6e6fSHawking Zhang 		if (adev->gfx.rlc.se0_tap_delays_ucode_size_bytes) {
472435d6e6fSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE0_TAP_DELAYS];
473435d6e6fSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_SE0_TAP_DELAYS;
474435d6e6fSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
475435d6e6fSHawking Zhang 			adev->firmware.fw_size +=
476435d6e6fSHawking Zhang 				ALIGN(adev->gfx.rlc.se0_tap_delays_ucode_size_bytes, PAGE_SIZE);
477435d6e6fSHawking Zhang 		}
478435d6e6fSHawking Zhang 
479435d6e6fSHawking Zhang 		if (adev->gfx.rlc.se1_tap_delays_ucode_size_bytes) {
480435d6e6fSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE1_TAP_DELAYS];
481435d6e6fSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_SE1_TAP_DELAYS;
482435d6e6fSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
483435d6e6fSHawking Zhang 			adev->firmware.fw_size +=
484435d6e6fSHawking Zhang 				ALIGN(adev->gfx.rlc.se1_tap_delays_ucode_size_bytes, PAGE_SIZE);
485435d6e6fSHawking Zhang 		}
486435d6e6fSHawking Zhang 
487435d6e6fSHawking Zhang 		if (adev->gfx.rlc.se2_tap_delays_ucode_size_bytes) {
488435d6e6fSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE2_TAP_DELAYS];
489435d6e6fSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_SE2_TAP_DELAYS;
490435d6e6fSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
491435d6e6fSHawking Zhang 			adev->firmware.fw_size +=
492435d6e6fSHawking Zhang 				ALIGN(adev->gfx.rlc.se2_tap_delays_ucode_size_bytes, PAGE_SIZE);
493435d6e6fSHawking Zhang 		}
494435d6e6fSHawking Zhang 
495435d6e6fSHawking Zhang 		if (adev->gfx.rlc.se3_tap_delays_ucode_size_bytes) {
496435d6e6fSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE3_TAP_DELAYS];
497435d6e6fSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_SE3_TAP_DELAYS;
498435d6e6fSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
499435d6e6fSHawking Zhang 			adev->firmware.fw_size +=
500435d6e6fSHawking Zhang 				ALIGN(adev->gfx.rlc.se3_tap_delays_ucode_size_bytes, PAGE_SIZE);
501435d6e6fSHawking Zhang 		}
502435d6e6fSHawking Zhang 	}
503435d6e6fSHawking Zhang }
504*5b415212SHawking Zhang 
505*5b415212SHawking Zhang int amdgpu_gfx_rlc_init_microcode(struct amdgpu_device *adev,
506*5b415212SHawking Zhang 				  uint16_t version_major,
507*5b415212SHawking Zhang 				  uint16_t version_minor)
508*5b415212SHawking Zhang {
509*5b415212SHawking Zhang 	int err;
510*5b415212SHawking Zhang 
511*5b415212SHawking Zhang 	if (version_major < 2) {
512*5b415212SHawking Zhang 		/* only support rlc_hdr v2.x and onwards */
513*5b415212SHawking Zhang 		dev_err(adev->dev, "unsupported rlc fw hdr\n");
514*5b415212SHawking Zhang 		return -EINVAL;
515*5b415212SHawking Zhang 	}
516*5b415212SHawking Zhang 
517*5b415212SHawking Zhang 	/* is_rlc_v2_1 is still used in APU code path */
518*5b415212SHawking Zhang 	if (version_major == 2 && version_minor == 1)
519*5b415212SHawking Zhang 		adev->gfx.rlc.is_rlc_v2_1 = true;
520*5b415212SHawking Zhang 
521*5b415212SHawking Zhang 	if (version_minor >= 0) {
522*5b415212SHawking Zhang 		err = amdgpu_gfx_rlc_init_microcode_v2_0(adev);
523*5b415212SHawking Zhang 		if (err) {
524*5b415212SHawking Zhang 			dev_err(adev->dev, "fail to init rlc v2_0 microcode\n");
525*5b415212SHawking Zhang 			return err;
526*5b415212SHawking Zhang 		}
527*5b415212SHawking Zhang 	}
528*5b415212SHawking Zhang 	if (version_minor >= 1)
529*5b415212SHawking Zhang 		amdgpu_gfx_rlc_init_microcode_v2_1(adev);
530*5b415212SHawking Zhang 	if (version_minor >= 2)
531*5b415212SHawking Zhang 		amdgpu_gfx_rlc_init_microcode_v2_2(adev);
532*5b415212SHawking Zhang 	if (version_minor == 3)
533*5b415212SHawking Zhang 		amdgpu_gfx_rlc_init_microcode_v2_3(adev);
534*5b415212SHawking Zhang 	if (version_minor == 4)
535*5b415212SHawking Zhang 		amdgpu_gfx_rlc_init_microcode_v2_4(adev);
536*5b415212SHawking Zhang 
537*5b415212SHawking Zhang 	return 0;
538*5b415212SHawking Zhang }
539