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,
96*58ab2c08SChristian König 				      AMDGPU_GEM_DOMAIN_VRAM |
97*58ab2c08SChristian König 				      AMDGPU_GEM_DOMAIN_GTT,
98106c7d61SLikun Gao 				      &adev->gfx.rlc.save_restore_obj,
99106c7d61SLikun Gao 				      &adev->gfx.rlc.save_restore_gpu_addr,
100106c7d61SLikun Gao 				      (void **)&adev->gfx.rlc.sr_ptr);
101106c7d61SLikun Gao 	if (r) {
102106c7d61SLikun Gao 		dev_warn(adev->dev, "(%d) create RLC sr bo failed\n", r);
103106c7d61SLikun Gao 		amdgpu_gfx_rlc_fini(adev);
104106c7d61SLikun Gao 		return r;
105106c7d61SLikun Gao 	}
106106c7d61SLikun Gao 
107106c7d61SLikun Gao 	/* write the sr buffer */
108106c7d61SLikun Gao 	src_ptr = adev->gfx.rlc.reg_list;
109106c7d61SLikun Gao 	dst_ptr = adev->gfx.rlc.sr_ptr;
110106c7d61SLikun Gao 	for (i = 0; i < adev->gfx.rlc.reg_list_size; i++)
111106c7d61SLikun Gao 		dst_ptr[i] = cpu_to_le32(src_ptr[i]);
112106c7d61SLikun Gao 	amdgpu_bo_kunmap(adev->gfx.rlc.save_restore_obj);
113106c7d61SLikun Gao 	amdgpu_bo_unreserve(adev->gfx.rlc.save_restore_obj);
114106c7d61SLikun Gao 
115106c7d61SLikun Gao 	return 0;
116106c7d61SLikun Gao }
117106c7d61SLikun Gao 
118106c7d61SLikun Gao /**
119106c7d61SLikun Gao  * amdgpu_gfx_rlc_init_csb - Init clear state block
120106c7d61SLikun Gao  *
121106c7d61SLikun Gao  * @adev: amdgpu_device pointer
122106c7d61SLikun Gao  *
123106c7d61SLikun Gao  * Allocate and setup value to clear state block of rlc.
124106c7d61SLikun Gao  * Returns 0 on succeess or negative error code if allocate failed.
125106c7d61SLikun Gao  */
126106c7d61SLikun Gao int amdgpu_gfx_rlc_init_csb(struct amdgpu_device *adev)
127106c7d61SLikun Gao {
128106c7d61SLikun Gao 	u32 dws;
129106c7d61SLikun Gao 	int r;
130106c7d61SLikun Gao 
131106c7d61SLikun Gao 	/* allocate clear state block */
132106c7d61SLikun Gao 	adev->gfx.rlc.clear_state_size = dws = adev->gfx.rlc.funcs->get_csb_size(adev);
133747d4f71SMonk Liu 	r = amdgpu_bo_create_kernel(adev, dws * 4, PAGE_SIZE,
134*58ab2c08SChristian König 				      AMDGPU_GEM_DOMAIN_VRAM |
135*58ab2c08SChristian König 				      AMDGPU_GEM_DOMAIN_GTT,
136106c7d61SLikun Gao 				      &adev->gfx.rlc.clear_state_obj,
137106c7d61SLikun Gao 				      &adev->gfx.rlc.clear_state_gpu_addr,
138106c7d61SLikun Gao 				      (void **)&adev->gfx.rlc.cs_ptr);
139106c7d61SLikun Gao 	if (r) {
140106c7d61SLikun Gao 		dev_err(adev->dev, "(%d) failed to create rlc csb bo\n", r);
141106c7d61SLikun Gao 		amdgpu_gfx_rlc_fini(adev);
142106c7d61SLikun Gao 		return r;
143106c7d61SLikun Gao 	}
144106c7d61SLikun Gao 
145106c7d61SLikun Gao 	return 0;
146106c7d61SLikun Gao }
147106c7d61SLikun Gao 
148106c7d61SLikun Gao /**
149106c7d61SLikun Gao  * amdgpu_gfx_rlc_init_cpt - Init cp table
150106c7d61SLikun Gao  *
151106c7d61SLikun Gao  * @adev: amdgpu_device pointer
152106c7d61SLikun Gao  *
153106c7d61SLikun Gao  * Allocate and setup value to cp table of rlc.
154106c7d61SLikun Gao  * Returns 0 on succeess or negative error code if allocate failed.
155106c7d61SLikun Gao  */
156106c7d61SLikun Gao int amdgpu_gfx_rlc_init_cpt(struct amdgpu_device *adev)
157106c7d61SLikun Gao {
158106c7d61SLikun Gao 	int r;
159106c7d61SLikun Gao 
160106c7d61SLikun Gao 	r = amdgpu_bo_create_reserved(adev, adev->gfx.rlc.cp_table_size,
161*58ab2c08SChristian König 				      PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM |
162*58ab2c08SChristian König 				      AMDGPU_GEM_DOMAIN_GTT,
163106c7d61SLikun Gao 				      &adev->gfx.rlc.cp_table_obj,
164106c7d61SLikun Gao 				      &adev->gfx.rlc.cp_table_gpu_addr,
165106c7d61SLikun Gao 				      (void **)&adev->gfx.rlc.cp_table_ptr);
166106c7d61SLikun Gao 	if (r) {
167106c7d61SLikun Gao 		dev_err(adev->dev, "(%d) failed to create cp table bo\n", r);
168106c7d61SLikun Gao 		amdgpu_gfx_rlc_fini(adev);
169106c7d61SLikun Gao 		return r;
170106c7d61SLikun Gao 	}
171106c7d61SLikun Gao 
172106c7d61SLikun Gao 	/* set up the cp table */
173106c7d61SLikun Gao 	amdgpu_gfx_rlc_setup_cp_table(adev);
174106c7d61SLikun Gao 	amdgpu_bo_kunmap(adev->gfx.rlc.cp_table_obj);
175106c7d61SLikun Gao 	amdgpu_bo_unreserve(adev->gfx.rlc.cp_table_obj);
176106c7d61SLikun Gao 
177106c7d61SLikun Gao 	return 0;
178106c7d61SLikun Gao }
179106c7d61SLikun Gao 
180106c7d61SLikun Gao /**
181106c7d61SLikun Gao  * amdgpu_gfx_rlc_setup_cp_table - setup cp the buffer of cp table
182106c7d61SLikun Gao  *
183106c7d61SLikun Gao  * @adev: amdgpu_device pointer
184106c7d61SLikun Gao  *
185106c7d61SLikun Gao  * Write cp firmware data into cp table.
186106c7d61SLikun Gao  */
187106c7d61SLikun Gao void amdgpu_gfx_rlc_setup_cp_table(struct amdgpu_device *adev)
188106c7d61SLikun Gao {
189106c7d61SLikun Gao 	const __le32 *fw_data;
190106c7d61SLikun Gao 	volatile u32 *dst_ptr;
191106c7d61SLikun Gao 	int me, i, max_me;
192106c7d61SLikun Gao 	u32 bo_offset = 0;
193106c7d61SLikun Gao 	u32 table_offset, table_size;
194106c7d61SLikun Gao 
195106c7d61SLikun Gao 	max_me = adev->gfx.rlc.funcs->get_cp_table_num(adev);
196106c7d61SLikun Gao 
197106c7d61SLikun Gao 	/* write the cp table buffer */
198106c7d61SLikun Gao 	dst_ptr = adev->gfx.rlc.cp_table_ptr;
199106c7d61SLikun Gao 	for (me = 0; me < max_me; me++) {
200106c7d61SLikun Gao 		if (me == 0) {
201106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
202106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.ce_fw->data;
203106c7d61SLikun Gao 			fw_data = (const __le32 *)
204106c7d61SLikun Gao 				(adev->gfx.ce_fw->data +
205106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
206106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
207106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
208106c7d61SLikun Gao 		} else if (me == 1) {
209106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
210106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.pfp_fw->data;
211106c7d61SLikun Gao 			fw_data = (const __le32 *)
212106c7d61SLikun Gao 				(adev->gfx.pfp_fw->data +
213106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
214106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
215106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
216106c7d61SLikun Gao 		} else if (me == 2) {
217106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
218106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.me_fw->data;
219106c7d61SLikun Gao 			fw_data = (const __le32 *)
220106c7d61SLikun Gao 				(adev->gfx.me_fw->data +
221106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
222106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
223106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
224106c7d61SLikun Gao 		} else if (me == 3) {
225106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
226106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.mec_fw->data;
227106c7d61SLikun Gao 			fw_data = (const __le32 *)
228106c7d61SLikun Gao 				(adev->gfx.mec_fw->data +
229106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
230106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
231106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
232106c7d61SLikun Gao 		} else  if (me == 4) {
233106c7d61SLikun Gao 			const struct gfx_firmware_header_v1_0 *hdr =
234106c7d61SLikun Gao 				(const struct gfx_firmware_header_v1_0 *)adev->gfx.mec2_fw->data;
235106c7d61SLikun Gao 			fw_data = (const __le32 *)
236106c7d61SLikun Gao 				(adev->gfx.mec2_fw->data +
237106c7d61SLikun Gao 				 le32_to_cpu(hdr->header.ucode_array_offset_bytes));
238106c7d61SLikun Gao 			table_offset = le32_to_cpu(hdr->jt_offset);
239106c7d61SLikun Gao 			table_size = le32_to_cpu(hdr->jt_size);
240106c7d61SLikun Gao 		}
241106c7d61SLikun Gao 
242106c7d61SLikun Gao 		for (i = 0; i < table_size; i ++) {
243106c7d61SLikun Gao 			dst_ptr[bo_offset + i] =
244106c7d61SLikun Gao 				cpu_to_le32(le32_to_cpu(fw_data[table_offset + i]));
245106c7d61SLikun Gao 		}
246106c7d61SLikun Gao 
247106c7d61SLikun Gao 		bo_offset += table_size;
248106c7d61SLikun Gao 	}
249106c7d61SLikun Gao }
250106c7d61SLikun Gao 
251106c7d61SLikun Gao /**
25288dfc9a3SLikun Gao  * amdgpu_gfx_rlc_fini - Free BO which used for RLC
25388dfc9a3SLikun Gao  *
25488dfc9a3SLikun Gao  * @adev: amdgpu_device pointer
25588dfc9a3SLikun Gao  *
25688dfc9a3SLikun Gao  * Free three BO which is used for rlc_save_restore_block, rlc_clear_state_block
25788dfc9a3SLikun Gao  * and rlc_jump_table_block.
25888dfc9a3SLikun Gao  */
25988dfc9a3SLikun Gao void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev)
26088dfc9a3SLikun Gao {
26188dfc9a3SLikun Gao 	/* save restore block */
26288dfc9a3SLikun Gao 	if (adev->gfx.rlc.save_restore_obj) {
26388dfc9a3SLikun Gao 		amdgpu_bo_free_kernel(&adev->gfx.rlc.save_restore_obj,
26488dfc9a3SLikun Gao 				      &adev->gfx.rlc.save_restore_gpu_addr,
26588dfc9a3SLikun Gao 				      (void **)&adev->gfx.rlc.sr_ptr);
26688dfc9a3SLikun Gao 	}
26788dfc9a3SLikun Gao 
26888dfc9a3SLikun Gao 	/* clear state block */
26988dfc9a3SLikun Gao 	amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj,
27088dfc9a3SLikun Gao 			      &adev->gfx.rlc.clear_state_gpu_addr,
27188dfc9a3SLikun Gao 			      (void **)&adev->gfx.rlc.cs_ptr);
27288dfc9a3SLikun Gao 
27388dfc9a3SLikun Gao 	/* jump table block */
27488dfc9a3SLikun Gao 	amdgpu_bo_free_kernel(&adev->gfx.rlc.cp_table_obj,
27588dfc9a3SLikun Gao 			      &adev->gfx.rlc.cp_table_gpu_addr,
27688dfc9a3SLikun Gao 			      (void **)&adev->gfx.rlc.cp_table_ptr);
27788dfc9a3SLikun Gao }
2780641dbefSHawking Zhang 
2790641dbefSHawking Zhang static int amdgpu_gfx_rlc_init_microcode_v2_0(struct amdgpu_device *adev)
2800641dbefSHawking Zhang {
2810641dbefSHawking Zhang 	const struct common_firmware_header *common_hdr;
2820641dbefSHawking Zhang 	const struct rlc_firmware_header_v2_0 *rlc_hdr;
2830641dbefSHawking Zhang 	struct amdgpu_firmware_info *info;
2840641dbefSHawking Zhang 	unsigned int *tmp;
2850641dbefSHawking Zhang 	unsigned int i;
2860641dbefSHawking Zhang 
2870641dbefSHawking Zhang 	rlc_hdr = (const struct rlc_firmware_header_v2_0 *)adev->gfx.rlc_fw->data;
2880641dbefSHawking Zhang 
2890641dbefSHawking Zhang 	adev->gfx.rlc_fw_version = le32_to_cpu(rlc_hdr->header.ucode_version);
2900641dbefSHawking Zhang 	adev->gfx.rlc_feature_version = le32_to_cpu(rlc_hdr->ucode_feature_version);
2910641dbefSHawking Zhang 	adev->gfx.rlc.save_and_restore_offset =
2920641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->save_and_restore_offset);
2930641dbefSHawking Zhang 	adev->gfx.rlc.clear_state_descriptor_offset =
2940641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->clear_state_descriptor_offset);
2950641dbefSHawking Zhang 	adev->gfx.rlc.avail_scratch_ram_locations =
2960641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->avail_scratch_ram_locations);
2970641dbefSHawking Zhang 	adev->gfx.rlc.reg_restore_list_size =
2980641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->reg_restore_list_size);
2990641dbefSHawking Zhang 	adev->gfx.rlc.reg_list_format_start =
3000641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->reg_list_format_start);
3010641dbefSHawking Zhang 	adev->gfx.rlc.reg_list_format_separate_start =
3020641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->reg_list_format_separate_start);
3030641dbefSHawking Zhang 	adev->gfx.rlc.starting_offsets_start =
3040641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->starting_offsets_start);
3050641dbefSHawking Zhang 	adev->gfx.rlc.reg_list_format_size_bytes =
3060641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->reg_list_format_size_bytes);
3070641dbefSHawking Zhang 	adev->gfx.rlc.reg_list_size_bytes =
3080641dbefSHawking Zhang 		le32_to_cpu(rlc_hdr->reg_list_size_bytes);
3090641dbefSHawking Zhang 	adev->gfx.rlc.register_list_format =
3100641dbefSHawking Zhang 		kmalloc(adev->gfx.rlc.reg_list_format_size_bytes +
3110641dbefSHawking Zhang 			adev->gfx.rlc.reg_list_size_bytes, GFP_KERNEL);
3120641dbefSHawking Zhang 	if (!adev->gfx.rlc.register_list_format) {
3130641dbefSHawking Zhang 		dev_err(adev->dev, "failed to allocate memory for rlc register_list_format\n");
3140641dbefSHawking Zhang 		return -ENOMEM;
3150641dbefSHawking Zhang 	}
3160641dbefSHawking Zhang 
3170641dbefSHawking Zhang 	tmp = (unsigned int *)((uintptr_t)rlc_hdr +
3180641dbefSHawking Zhang 			le32_to_cpu(rlc_hdr->reg_list_format_array_offset_bytes));
3190641dbefSHawking Zhang 	for (i = 0 ; i < (rlc_hdr->reg_list_format_size_bytes >> 2); i++)
3200641dbefSHawking Zhang 		adev->gfx.rlc.register_list_format[i] = le32_to_cpu(tmp[i]);
3210641dbefSHawking Zhang 
3220641dbefSHawking Zhang 	adev->gfx.rlc.register_restore = adev->gfx.rlc.register_list_format + i;
3230641dbefSHawking Zhang 
3240641dbefSHawking Zhang 	tmp = (unsigned int *)((uintptr_t)rlc_hdr +
3250641dbefSHawking Zhang 			le32_to_cpu(rlc_hdr->reg_list_array_offset_bytes));
3260641dbefSHawking Zhang 	for (i = 0 ; i < (rlc_hdr->reg_list_size_bytes >> 2); i++)
3270641dbefSHawking Zhang 		adev->gfx.rlc.register_restore[i] = le32_to_cpu(tmp[i]);
3280641dbefSHawking Zhang 
3290641dbefSHawking Zhang 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
3300641dbefSHawking Zhang 		info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_G];
3310641dbefSHawking Zhang 		info->ucode_id = AMDGPU_UCODE_ID_RLC_G;
3320641dbefSHawking Zhang 		info->fw = adev->gfx.rlc_fw;
3330641dbefSHawking Zhang 		if (info->fw) {
3340641dbefSHawking Zhang 			common_hdr = (const struct common_firmware_header *)info->fw->data;
3350641dbefSHawking Zhang 			adev->firmware.fw_size +=
3360641dbefSHawking Zhang 				ALIGN(le32_to_cpu(common_hdr->ucode_size_bytes), PAGE_SIZE);
3370641dbefSHawking Zhang 		}
3380641dbefSHawking Zhang 	}
3390641dbefSHawking Zhang 
3400641dbefSHawking Zhang 	return 0;
3410641dbefSHawking Zhang }
342f3e6173bSHawking Zhang 
343f3e6173bSHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_1(struct amdgpu_device *adev)
344f3e6173bSHawking Zhang {
345f3e6173bSHawking Zhang 	const struct rlc_firmware_header_v2_1 *rlc_hdr;
346f3e6173bSHawking Zhang 	struct amdgpu_firmware_info *info;
347f3e6173bSHawking Zhang 
348f3e6173bSHawking Zhang 	rlc_hdr = (const struct rlc_firmware_header_v2_1 *)adev->gfx.rlc_fw->data;
349f3e6173bSHawking Zhang 	adev->gfx.rlc_srlc_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_ucode_ver);
350f3e6173bSHawking Zhang 	adev->gfx.rlc_srlc_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_cntl_feature_ver);
351f3e6173bSHawking Zhang 	adev->gfx.rlc.save_restore_list_cntl_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_cntl_size_bytes);
352f3e6173bSHawking Zhang 	adev->gfx.rlc.save_restore_list_cntl = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_cntl_offset_bytes);
353f3e6173bSHawking Zhang 	adev->gfx.rlc_srlg_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_ucode_ver);
354f3e6173bSHawking Zhang 	adev->gfx.rlc_srlg_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_gpm_feature_ver);
355f3e6173bSHawking Zhang 	adev->gfx.rlc.save_restore_list_gpm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_gpm_size_bytes);
356f3e6173bSHawking Zhang 	adev->gfx.rlc.save_restore_list_gpm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_gpm_offset_bytes);
357f3e6173bSHawking Zhang 	adev->gfx.rlc_srls_fw_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_ucode_ver);
358f3e6173bSHawking Zhang 	adev->gfx.rlc_srls_feature_version = le32_to_cpu(rlc_hdr->save_restore_list_srm_feature_ver);
359f3e6173bSHawking Zhang 	adev->gfx.rlc.save_restore_list_srm_size_bytes = le32_to_cpu(rlc_hdr->save_restore_list_srm_size_bytes);
360f3e6173bSHawking Zhang 	adev->gfx.rlc.save_restore_list_srm = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->save_restore_list_srm_offset_bytes);
361f3e6173bSHawking Zhang 	adev->gfx.rlc.reg_list_format_direct_reg_list_length =
362f3e6173bSHawking Zhang 		le32_to_cpu(rlc_hdr->reg_list_format_direct_reg_list_length);
363f3e6173bSHawking Zhang 
364f3e6173bSHawking Zhang 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
365940d4dd4SHawking Zhang 		if (adev->gfx.rlc.save_restore_list_cntl_size_bytes) {
366940d4dd4SHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL];
367940d4dd4SHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL;
368940d4dd4SHawking Zhang 			info->fw = adev->gfx.rlc_fw;
369940d4dd4SHawking Zhang 			adev->firmware.fw_size +=
370940d4dd4SHawking Zhang 				ALIGN(adev->gfx.rlc.save_restore_list_cntl_size_bytes, PAGE_SIZE);
371940d4dd4SHawking Zhang 		}
372940d4dd4SHawking Zhang 
373f3e6173bSHawking Zhang 		if (adev->gfx.rlc.save_restore_list_gpm_size_bytes) {
374f3e6173bSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM];
375f3e6173bSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM;
376f3e6173bSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
377f3e6173bSHawking Zhang 			adev->firmware.fw_size +=
378f3e6173bSHawking Zhang 				ALIGN(adev->gfx.rlc.save_restore_list_gpm_size_bytes, PAGE_SIZE);
379f3e6173bSHawking Zhang 		}
380f3e6173bSHawking Zhang 
381f3e6173bSHawking Zhang 		if (adev->gfx.rlc.save_restore_list_srm_size_bytes) {
382f3e6173bSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM];
383f3e6173bSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM;
384f3e6173bSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
385f3e6173bSHawking Zhang 			adev->firmware.fw_size +=
386f3e6173bSHawking Zhang 				ALIGN(adev->gfx.rlc.save_restore_list_srm_size_bytes, PAGE_SIZE);
387f3e6173bSHawking Zhang 		}
388f3e6173bSHawking Zhang 	}
389f3e6173bSHawking Zhang }
390a97d0ec8SHawking Zhang 
391a97d0ec8SHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_2(struct amdgpu_device *adev)
392a97d0ec8SHawking Zhang {
393a97d0ec8SHawking Zhang 	const struct rlc_firmware_header_v2_2 *rlc_hdr;
394a97d0ec8SHawking Zhang 	struct amdgpu_firmware_info *info;
395a97d0ec8SHawking Zhang 
396a97d0ec8SHawking Zhang 	rlc_hdr = (const struct rlc_firmware_header_v2_2 *)adev->gfx.rlc_fw->data;
397a97d0ec8SHawking Zhang 	adev->gfx.rlc.rlc_iram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_iram_ucode_size_bytes);
398a97d0ec8SHawking Zhang 	adev->gfx.rlc.rlc_iram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_iram_ucode_offset_bytes);
399a97d0ec8SHawking Zhang 	adev->gfx.rlc.rlc_dram_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlc_dram_ucode_size_bytes);
400a97d0ec8SHawking Zhang 	adev->gfx.rlc.rlc_dram_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlc_dram_ucode_offset_bytes);
401a97d0ec8SHawking Zhang 
402a97d0ec8SHawking Zhang 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
403a97d0ec8SHawking Zhang 		if (adev->gfx.rlc.rlc_iram_ucode_size_bytes) {
404a97d0ec8SHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_IRAM];
405a97d0ec8SHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_RLC_IRAM;
406a97d0ec8SHawking Zhang 			info->fw = adev->gfx.rlc_fw;
407a97d0ec8SHawking Zhang 			adev->firmware.fw_size +=
408a97d0ec8SHawking Zhang 				ALIGN(adev->gfx.rlc.rlc_iram_ucode_size_bytes, PAGE_SIZE);
409a97d0ec8SHawking Zhang 		}
410a97d0ec8SHawking Zhang 
411a97d0ec8SHawking Zhang 		if (adev->gfx.rlc.rlc_dram_ucode_size_bytes) {
412a97d0ec8SHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_DRAM];
413a97d0ec8SHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_RLC_DRAM;
414a97d0ec8SHawking Zhang 			info->fw = adev->gfx.rlc_fw;
415a97d0ec8SHawking Zhang 			adev->firmware.fw_size +=
416a97d0ec8SHawking Zhang 				ALIGN(adev->gfx.rlc.rlc_dram_ucode_size_bytes, PAGE_SIZE);
417a97d0ec8SHawking Zhang 		}
418a97d0ec8SHawking Zhang 	}
419a97d0ec8SHawking Zhang }
420a0d9084dSHawking Zhang 
421a0d9084dSHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_3(struct amdgpu_device *adev)
422a0d9084dSHawking Zhang {
423a0d9084dSHawking Zhang 	const struct rlc_firmware_header_v2_3 *rlc_hdr;
424a0d9084dSHawking Zhang 	struct amdgpu_firmware_info *info;
425a0d9084dSHawking Zhang 
426a0d9084dSHawking Zhang 	rlc_hdr = (const struct rlc_firmware_header_v2_3 *)adev->gfx.rlc_fw->data;
427a0d9084dSHawking Zhang 	adev->gfx.rlcp_ucode_version = le32_to_cpu(rlc_hdr->rlcp_ucode_version);
428a0d9084dSHawking Zhang 	adev->gfx.rlcp_ucode_feature_version = le32_to_cpu(rlc_hdr->rlcp_ucode_feature_version);
429a0d9084dSHawking Zhang 	adev->gfx.rlc.rlcp_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlcp_ucode_size_bytes);
430a0d9084dSHawking Zhang 	adev->gfx.rlc.rlcp_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlcp_ucode_offset_bytes);
431a0d9084dSHawking Zhang 
432a0d9084dSHawking Zhang 	adev->gfx.rlcv_ucode_version = le32_to_cpu(rlc_hdr->rlcv_ucode_version);
433a0d9084dSHawking Zhang 	adev->gfx.rlcv_ucode_feature_version = le32_to_cpu(rlc_hdr->rlcv_ucode_feature_version);
434a0d9084dSHawking Zhang 	adev->gfx.rlc.rlcv_ucode_size_bytes = le32_to_cpu(rlc_hdr->rlcv_ucode_size_bytes);
435a0d9084dSHawking Zhang 	adev->gfx.rlc.rlcv_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->rlcv_ucode_offset_bytes);
436a0d9084dSHawking Zhang 
437a0d9084dSHawking Zhang 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
438a0d9084dSHawking Zhang 		if (adev->gfx.rlc.rlcp_ucode_size_bytes) {
439a0d9084dSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_P];
440a0d9084dSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_RLC_P;
441a0d9084dSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
442a0d9084dSHawking Zhang 			adev->firmware.fw_size +=
443a0d9084dSHawking Zhang 				ALIGN(adev->gfx.rlc.rlcp_ucode_size_bytes, PAGE_SIZE);
444a0d9084dSHawking Zhang 		}
445a0d9084dSHawking Zhang 
446a0d9084dSHawking Zhang 		if (adev->gfx.rlc.rlcv_ucode_size_bytes) {
447a0d9084dSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_RLC_V];
448a0d9084dSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_RLC_V;
449a0d9084dSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
450a0d9084dSHawking Zhang 			adev->firmware.fw_size +=
451a0d9084dSHawking Zhang 				ALIGN(adev->gfx.rlc.rlcv_ucode_size_bytes, PAGE_SIZE);
452a0d9084dSHawking Zhang 		}
453a0d9084dSHawking Zhang 	}
454a0d9084dSHawking Zhang }
455435d6e6fSHawking Zhang 
456435d6e6fSHawking Zhang static void amdgpu_gfx_rlc_init_microcode_v2_4(struct amdgpu_device *adev)
457435d6e6fSHawking Zhang {
458435d6e6fSHawking Zhang 	const struct rlc_firmware_header_v2_4 *rlc_hdr;
459435d6e6fSHawking Zhang 	struct amdgpu_firmware_info *info;
460435d6e6fSHawking Zhang 
461435d6e6fSHawking Zhang 	rlc_hdr = (const struct rlc_firmware_header_v2_4 *)adev->gfx.rlc_fw->data;
462435d6e6fSHawking Zhang 	adev->gfx.rlc.global_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->global_tap_delays_ucode_size_bytes);
463435d6e6fSHawking Zhang 	adev->gfx.rlc.global_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->global_tap_delays_ucode_offset_bytes);
464435d6e6fSHawking Zhang 	adev->gfx.rlc.se0_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se0_tap_delays_ucode_size_bytes);
465435d6e6fSHawking Zhang 	adev->gfx.rlc.se0_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se0_tap_delays_ucode_offset_bytes);
466435d6e6fSHawking Zhang 	adev->gfx.rlc.se1_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se1_tap_delays_ucode_size_bytes);
467435d6e6fSHawking Zhang 	adev->gfx.rlc.se1_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se1_tap_delays_ucode_offset_bytes);
468435d6e6fSHawking Zhang 	adev->gfx.rlc.se2_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se2_tap_delays_ucode_size_bytes);
469435d6e6fSHawking Zhang 	adev->gfx.rlc.se2_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se2_tap_delays_ucode_offset_bytes);
470435d6e6fSHawking Zhang 	adev->gfx.rlc.se3_tap_delays_ucode_size_bytes = le32_to_cpu(rlc_hdr->se3_tap_delays_ucode_size_bytes);
471435d6e6fSHawking Zhang 	adev->gfx.rlc.se3_tap_delays_ucode = (u8 *)rlc_hdr + le32_to_cpu(rlc_hdr->se3_tap_delays_ucode_offset_bytes);
472435d6e6fSHawking Zhang 
473435d6e6fSHawking Zhang 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) {
474435d6e6fSHawking Zhang 		if (adev->gfx.rlc.global_tap_delays_ucode_size_bytes) {
475435d6e6fSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS];
476435d6e6fSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_GLOBAL_TAP_DELAYS;
477435d6e6fSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
478435d6e6fSHawking Zhang 			adev->firmware.fw_size +=
479435d6e6fSHawking Zhang 				ALIGN(adev->gfx.rlc.global_tap_delays_ucode_size_bytes, PAGE_SIZE);
480435d6e6fSHawking Zhang 		}
481435d6e6fSHawking Zhang 
482435d6e6fSHawking Zhang 		if (adev->gfx.rlc.se0_tap_delays_ucode_size_bytes) {
483435d6e6fSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE0_TAP_DELAYS];
484435d6e6fSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_SE0_TAP_DELAYS;
485435d6e6fSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
486435d6e6fSHawking Zhang 			adev->firmware.fw_size +=
487435d6e6fSHawking Zhang 				ALIGN(adev->gfx.rlc.se0_tap_delays_ucode_size_bytes, PAGE_SIZE);
488435d6e6fSHawking Zhang 		}
489435d6e6fSHawking Zhang 
490435d6e6fSHawking Zhang 		if (adev->gfx.rlc.se1_tap_delays_ucode_size_bytes) {
491435d6e6fSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE1_TAP_DELAYS];
492435d6e6fSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_SE1_TAP_DELAYS;
493435d6e6fSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
494435d6e6fSHawking Zhang 			adev->firmware.fw_size +=
495435d6e6fSHawking Zhang 				ALIGN(adev->gfx.rlc.se1_tap_delays_ucode_size_bytes, PAGE_SIZE);
496435d6e6fSHawking Zhang 		}
497435d6e6fSHawking Zhang 
498435d6e6fSHawking Zhang 		if (adev->gfx.rlc.se2_tap_delays_ucode_size_bytes) {
499435d6e6fSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE2_TAP_DELAYS];
500435d6e6fSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_SE2_TAP_DELAYS;
501435d6e6fSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
502435d6e6fSHawking Zhang 			adev->firmware.fw_size +=
503435d6e6fSHawking Zhang 				ALIGN(adev->gfx.rlc.se2_tap_delays_ucode_size_bytes, PAGE_SIZE);
504435d6e6fSHawking Zhang 		}
505435d6e6fSHawking Zhang 
506435d6e6fSHawking Zhang 		if (adev->gfx.rlc.se3_tap_delays_ucode_size_bytes) {
507435d6e6fSHawking Zhang 			info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SE3_TAP_DELAYS];
508435d6e6fSHawking Zhang 			info->ucode_id = AMDGPU_UCODE_ID_SE3_TAP_DELAYS;
509435d6e6fSHawking Zhang 			info->fw = adev->gfx.rlc_fw;
510435d6e6fSHawking Zhang 			adev->firmware.fw_size +=
511435d6e6fSHawking Zhang 				ALIGN(adev->gfx.rlc.se3_tap_delays_ucode_size_bytes, PAGE_SIZE);
512435d6e6fSHawking Zhang 		}
513435d6e6fSHawking Zhang 	}
514435d6e6fSHawking Zhang }
5155b415212SHawking Zhang 
5165b415212SHawking Zhang int amdgpu_gfx_rlc_init_microcode(struct amdgpu_device *adev,
5175b415212SHawking Zhang 				  uint16_t version_major,
5185b415212SHawking Zhang 				  uint16_t version_minor)
5195b415212SHawking Zhang {
5205b415212SHawking Zhang 	int err;
5215b415212SHawking Zhang 
5225b415212SHawking Zhang 	if (version_major < 2) {
5235b415212SHawking Zhang 		/* only support rlc_hdr v2.x and onwards */
5245b415212SHawking Zhang 		dev_err(adev->dev, "unsupported rlc fw hdr\n");
5255b415212SHawking Zhang 		return -EINVAL;
5265b415212SHawking Zhang 	}
5275b415212SHawking Zhang 
5285b415212SHawking Zhang 	/* is_rlc_v2_1 is still used in APU code path */
5295b415212SHawking Zhang 	if (version_major == 2 && version_minor == 1)
5305b415212SHawking Zhang 		adev->gfx.rlc.is_rlc_v2_1 = true;
5315b415212SHawking Zhang 
5325b415212SHawking Zhang 	if (version_minor >= 0) {
5335b415212SHawking Zhang 		err = amdgpu_gfx_rlc_init_microcode_v2_0(adev);
5345b415212SHawking Zhang 		if (err) {
5355b415212SHawking Zhang 			dev_err(adev->dev, "fail to init rlc v2_0 microcode\n");
5365b415212SHawking Zhang 			return err;
5375b415212SHawking Zhang 		}
5385b415212SHawking Zhang 	}
5395b415212SHawking Zhang 	if (version_minor >= 1)
5405b415212SHawking Zhang 		amdgpu_gfx_rlc_init_microcode_v2_1(adev);
5415b415212SHawking Zhang 	if (version_minor >= 2)
5425b415212SHawking Zhang 		amdgpu_gfx_rlc_init_microcode_v2_2(adev);
5435b415212SHawking Zhang 	if (version_minor == 3)
5445b415212SHawking Zhang 		amdgpu_gfx_rlc_init_microcode_v2_3(adev);
5455b415212SHawking Zhang 	if (version_minor == 4)
5465b415212SHawking Zhang 		amdgpu_gfx_rlc_init_microcode_v2_4(adev);
5475b415212SHawking Zhang 
5485b415212SHawking Zhang 	return 0;
5495b415212SHawking Zhang }
550