• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Author: Huang Rui <ray.huang@amd.com>
23  *
24  */
25 #include <linux/types.h>
26 #include <linux/kernel.h>
27 #include <linux/slab.h>
28 #include <linux/gfp.h>
29 
30 #include "smumgr.h"
31 #include "iceland_smumgr.h"
32 #include "pp_debug.h"
33 #include "smu_ucode_xfer_vi.h"
34 #include "ppsmc.h"
35 #include "smu/smu_7_1_1_d.h"
36 #include "smu/smu_7_1_1_sh_mask.h"
37 #include "cgs_common.h"
38 #include "iceland_smc.h"
39 
40 #define ICELAND_SMC_SIZE               0x20000
41 
iceland_start_smc(struct pp_smumgr * smumgr)42 static int iceland_start_smc(struct pp_smumgr *smumgr)
43 {
44 	SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
45 				  SMC_SYSCON_RESET_CNTL, rst_reg, 0);
46 
47 	return 0;
48 }
49 
iceland_reset_smc(struct pp_smumgr * smumgr)50 static void iceland_reset_smc(struct pp_smumgr *smumgr)
51 {
52 	SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
53 				  SMC_SYSCON_RESET_CNTL,
54 				  rst_reg, 1);
55 }
56 
57 
iceland_stop_smc_clock(struct pp_smumgr * smumgr)58 static void iceland_stop_smc_clock(struct pp_smumgr *smumgr)
59 {
60 	SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
61 				  SMC_SYSCON_CLOCK_CNTL_0,
62 				  ck_disable, 1);
63 }
64 
iceland_start_smc_clock(struct pp_smumgr * smumgr)65 static void iceland_start_smc_clock(struct pp_smumgr *smumgr)
66 {
67 	SMUM_WRITE_INDIRECT_FIELD(smumgr->device, CGS_IND_REG__SMC,
68 				  SMC_SYSCON_CLOCK_CNTL_0,
69 				  ck_disable, 0);
70 }
71 
iceland_smu_start_smc(struct pp_smumgr * smumgr)72 static int iceland_smu_start_smc(struct pp_smumgr *smumgr)
73 {
74 	/* set smc instruct start point at 0x0 */
75 	smu7_program_jump_on_start(smumgr);
76 
77 	/* enable smc clock */
78 	iceland_start_smc_clock(smumgr);
79 
80 	/* de-assert reset */
81 	iceland_start_smc(smumgr);
82 
83 	SMUM_WAIT_INDIRECT_FIELD(smumgr, SMC_IND, FIRMWARE_FLAGS,
84 				 INTERRUPTS_ENABLED, 1);
85 
86 	return 0;
87 }
88 
89 
iceland_upload_smc_firmware_data(struct pp_smumgr * smumgr,uint32_t length,const uint8_t * src,uint32_t limit,uint32_t start_addr)90 static int iceland_upload_smc_firmware_data(struct pp_smumgr *smumgr,
91 					uint32_t length, const uint8_t *src,
92 					uint32_t limit, uint32_t start_addr)
93 {
94 	uint32_t byte_count = length;
95 	uint32_t data;
96 
97 	PP_ASSERT_WITH_CODE((limit >= byte_count), "SMC address is beyond the SMC RAM area.", return -EINVAL);
98 
99 	cgs_write_register(smumgr->device, mmSMC_IND_INDEX_0, start_addr);
100 	SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 1);
101 
102 	while (byte_count >= 4) {
103 		data = src[0] * 0x1000000 + src[1] * 0x10000 + src[2] * 0x100 + src[3];
104 		cgs_write_register(smumgr->device, mmSMC_IND_DATA_0, data);
105 		src += 4;
106 		byte_count -= 4;
107 	}
108 
109 	SMUM_WRITE_FIELD(smumgr->device, SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, 0);
110 
111 	PP_ASSERT_WITH_CODE((0 == byte_count), "SMC size must be dividable by 4.", return -EINVAL);
112 
113 	return 0;
114 }
115 
116 
iceland_smu_upload_firmware_image(struct pp_smumgr * smumgr)117 static int iceland_smu_upload_firmware_image(struct pp_smumgr *smumgr)
118 {
119 	uint32_t val;
120 	struct cgs_firmware_info info = {0};
121 
122 	if (smumgr == NULL || smumgr->device == NULL)
123 		return -EINVAL;
124 
125 	/* load SMC firmware */
126 	cgs_get_firmware_info(smumgr->device,
127 		smu7_convert_fw_type_to_cgs(UCODE_ID_SMU), &info);
128 
129 	if (info.image_size & 3) {
130 		pr_err("[ powerplay ] SMC ucode is not 4 bytes aligned\n");
131 		return -EINVAL;
132 	}
133 
134 	if (info.image_size > ICELAND_SMC_SIZE) {
135 		pr_err("[ powerplay ] SMC address is beyond the SMC RAM area\n");
136 		return -EINVAL;
137 	}
138 
139 	/* wait for smc boot up */
140 	SMUM_WAIT_INDIRECT_FIELD_UNEQUAL(smumgr, SMC_IND,
141 					 RCU_UC_EVENTS, boot_seq_done, 0);
142 
143 	/* clear firmware interrupt enable flag */
144 	val = cgs_read_ind_register(smumgr->device, CGS_IND_REG__SMC,
145 				    ixSMC_SYSCON_MISC_CNTL);
146 	cgs_write_ind_register(smumgr->device, CGS_IND_REG__SMC,
147 			       ixSMC_SYSCON_MISC_CNTL, val | 1);
148 
149 	/* stop smc clock */
150 	iceland_stop_smc_clock(smumgr);
151 
152 	/* reset smc */
153 	iceland_reset_smc(smumgr);
154 	iceland_upload_smc_firmware_data(smumgr, info.image_size,
155 				(uint8_t *)info.kptr, ICELAND_SMC_SIZE,
156 				info.ucode_start_address);
157 
158 	return 0;
159 }
160 
iceland_request_smu_load_specific_fw(struct pp_smumgr * smumgr,uint32_t firmwareType)161 static int iceland_request_smu_load_specific_fw(struct pp_smumgr *smumgr,
162 						uint32_t firmwareType)
163 {
164 	return 0;
165 }
166 
iceland_start_smu(struct pp_smumgr * smumgr)167 static int iceland_start_smu(struct pp_smumgr *smumgr)
168 {
169 	int result;
170 
171 	result = iceland_smu_upload_firmware_image(smumgr);
172 	if (result)
173 		return result;
174 	result = iceland_smu_start_smc(smumgr);
175 	if (result)
176 		return result;
177 
178 	if (!smu7_is_smc_ram_running(smumgr)) {
179 		printk("smu not running, upload firmware again \n");
180 		result = iceland_smu_upload_firmware_image(smumgr);
181 		if (result)
182 			return result;
183 
184 		result = iceland_smu_start_smc(smumgr);
185 		if (result)
186 			return result;
187 	}
188 
189 	result = smu7_request_smu_load_fw(smumgr);
190 
191 	return result;
192 }
193 
194 /**
195  * Write a 32bit value to the SMC SRAM space.
196  * ALL PARAMETERS ARE IN HOST BYTE ORDER.
197  * @param    smumgr  the address of the powerplay hardware manager.
198  * @param    smcAddress the address in the SMC RAM to access.
199  * @param    value to write to the SMC SRAM.
200  */
iceland_smu_init(struct pp_smumgr * smumgr)201 static int iceland_smu_init(struct pp_smumgr *smumgr)
202 {
203 	int i;
204 	struct iceland_smumgr *smu_data = (struct iceland_smumgr *)(smumgr->backend);
205 	if (smu7_init(smumgr))
206 		return -EINVAL;
207 
208 	for (i = 0; i < SMU71_MAX_LEVELS_GRAPHICS; i++)
209 		smu_data->activity_target[i] = 30;
210 
211 	return 0;
212 }
213 
214 static const struct pp_smumgr_func iceland_smu_funcs = {
215 	.smu_init = &iceland_smu_init,
216 	.smu_fini = &smu7_smu_fini,
217 	.start_smu = &iceland_start_smu,
218 	.check_fw_load_finish = &smu7_check_fw_load_finish,
219 	.request_smu_load_fw = &smu7_reload_firmware,
220 	.request_smu_load_specific_fw = &iceland_request_smu_load_specific_fw,
221 	.send_msg_to_smc = &smu7_send_msg_to_smc,
222 	.send_msg_to_smc_with_parameter = &smu7_send_msg_to_smc_with_parameter,
223 	.download_pptable_settings = NULL,
224 	.upload_pptable_settings = NULL,
225 	.get_offsetof = iceland_get_offsetof,
226 	.process_firmware_header = iceland_process_firmware_header,
227 	.init_smc_table = iceland_init_smc_table,
228 	.update_sclk_threshold = iceland_update_sclk_threshold,
229 	.thermal_setup_fan_table = iceland_thermal_setup_fan_table,
230 	.populate_all_graphic_levels = iceland_populate_all_graphic_levels,
231 	.populate_all_memory_levels = iceland_populate_all_memory_levels,
232 	.get_mac_definition = iceland_get_mac_definition,
233 	.initialize_mc_reg_table = iceland_initialize_mc_reg_table,
234 	.is_dpm_running = iceland_is_dpm_running,
235 };
236 
iceland_smum_init(struct pp_smumgr * smumgr)237 int iceland_smum_init(struct pp_smumgr *smumgr)
238 {
239 	struct iceland_smumgr *iceland_smu = NULL;
240 
241 	iceland_smu = kzalloc(sizeof(struct iceland_smumgr), GFP_KERNEL);
242 
243 	if (iceland_smu == NULL)
244 		return -ENOMEM;
245 
246 	smumgr->backend = iceland_smu;
247 	smumgr->smumgr_funcs = &iceland_smu_funcs;
248 
249 	return 0;
250 }
251