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 */
23
24#include "smumgr.h"
25#include "smu10_inc.h"
26#include "soc15_common.h"
27#include "smu10_smumgr.h"
28#include "ppatomctrl.h"
29#include "rv_ppsmc.h"
30#include "smu10_driver_if.h"
31#include "smu10.h"
32#include "pp_debug.h"
33
34
35#define BUFFER_SIZE 80000
36#define MAX_STRING_SIZE 15
37#define BUFFER_SIZETWO 131072
38
39#define MP0_Public 0x03800000
40#define MP0_SRAM 0x03900000
41#define MP1_Public 0x03b00000
42#define MP1_SRAM 0x03c00004
43
44#define smnMP1_FIRMWARE_FLAGS 0x3010028
45
46
47static uint32_t smu10_wait_for_response(struct pp_hwmgr *hwmgr)
48{
49 struct amdgpu_device *adev = hwmgr->adev;
50 uint32_t reg;
51
52 reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90);
53
54 phm_wait_for_register_unequal(hwmgr, reg,
55 0, MP1_C2PMSG_90__CONTENT_MASK);
56
57 return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90);
58}
59
60static int smu10_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr,
61 uint16_t msg)
62{
63 struct amdgpu_device *adev = hwmgr->adev;
64
65 WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_66, msg);
66
67 return 0;
68}
69
70static uint32_t smu10_read_arg_from_smc(struct pp_hwmgr *hwmgr)
71{
72 struct amdgpu_device *adev = hwmgr->adev;
73
74 return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82);
75}
76
77static int smu10_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg)
78{
79 struct amdgpu_device *adev = hwmgr->adev;
80
81 smu10_wait_for_response(hwmgr);
82
83 WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0);
84
85 smu10_send_msg_to_smc_without_waiting(hwmgr, msg);
86
87 if (smu10_wait_for_response(hwmgr) == 0)
88 printk("Failed to send Message %x.\n", msg);
89
90 return 0;
91}
92
93
94static int smu10_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr,
95 uint16_t msg, uint32_t parameter)
96{
97 struct amdgpu_device *adev = hwmgr->adev;
98
99 smu10_wait_for_response(hwmgr);
100
101 WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0);
102
103 WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82, parameter);
104
105 smu10_send_msg_to_smc_without_waiting(hwmgr, msg);
106
107
108 if (smu10_wait_for_response(hwmgr) == 0)
109 printk("Failed to send Message %x.\n", msg);
110
111 return 0;
112}
113
114static int smu10_copy_table_from_smc(struct pp_hwmgr *hwmgr,
115 uint8_t *table, int16_t table_id)
116{
117 struct smu10_smumgr *priv =
118 (struct smu10_smumgr *)(hwmgr->smu_backend);
119
120 PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE,
121 "Invalid SMU Table ID!", return -EINVAL;);
122 PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0,
123 "Invalid SMU Table version!", return -EINVAL;);
124 PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0,
125 "Invalid SMU Table Length!", return -EINVAL;);
126 smu10_send_msg_to_smc_with_parameter(hwmgr,
127 PPSMC_MSG_SetDriverDramAddrHigh,
128 upper_32_bits(priv->smu_tables.entry[table_id].mc_addr));
129 smu10_send_msg_to_smc_with_parameter(hwmgr,
130 PPSMC_MSG_SetDriverDramAddrLow,
131 lower_32_bits(priv->smu_tables.entry[table_id].mc_addr));
132 smu10_send_msg_to_smc_with_parameter(hwmgr,
133 PPSMC_MSG_TransferTableSmu2Dram,
134 priv->smu_tables.entry[table_id].table_id);
135
136 memcpy(table, (uint8_t *)priv->smu_tables.entry[table_id].table,
137 priv->smu_tables.entry[table_id].size);
138
139 return 0;
140}
141
142static int smu10_copy_table_to_smc(struct pp_hwmgr *hwmgr,
143 uint8_t *table, int16_t table_id)
144{
145 struct smu10_smumgr *priv =
146 (struct smu10_smumgr *)(hwmgr->smu_backend);
147
148 PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE,
149 "Invalid SMU Table ID!", return -EINVAL;);
150 PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0,
151 "Invalid SMU Table version!", return -EINVAL;);
152 PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0,
153 "Invalid SMU Table Length!", return -EINVAL;);
154
155 memcpy(priv->smu_tables.entry[table_id].table, table,
156 priv->smu_tables.entry[table_id].size);
157
158 smu10_send_msg_to_smc_with_parameter(hwmgr,
159 PPSMC_MSG_SetDriverDramAddrHigh,
160 upper_32_bits(priv->smu_tables.entry[table_id].mc_addr));
161 smu10_send_msg_to_smc_with_parameter(hwmgr,
162 PPSMC_MSG_SetDriverDramAddrLow,
163 lower_32_bits(priv->smu_tables.entry[table_id].mc_addr));
164 smu10_send_msg_to_smc_with_parameter(hwmgr,
165 PPSMC_MSG_TransferTableDram2Smu,
166 priv->smu_tables.entry[table_id].table_id);
167
168 return 0;
169}
170
171static int smu10_verify_smc_interface(struct pp_hwmgr *hwmgr)
172{
173 uint32_t smc_driver_if_version;
174
175 smu10_send_msg_to_smc(hwmgr,
176 PPSMC_MSG_GetDriverIfVersion);
177 smc_driver_if_version = smu10_read_arg_from_smc(hwmgr);
178
179 if ((smc_driver_if_version != SMU10_DRIVER_IF_VERSION) &&
180 (smc_driver_if_version != SMU10_DRIVER_IF_VERSION + 1)) {
181 pr_err("Attempt to read SMC IF Version Number Failed!\n");
182 return -EINVAL;
183 }
184
185 return 0;
186}
187
188static int smu10_smu_fini(struct pp_hwmgr *hwmgr)
189{
190 struct smu10_smumgr *priv =
191 (struct smu10_smumgr *)(hwmgr->smu_backend);
192
193 if (priv) {
194 amdgpu_bo_free_kernel(&priv->smu_tables.entry[SMU10_WMTABLE].handle,
195 &priv->smu_tables.entry[SMU10_WMTABLE].mc_addr,
196 &priv->smu_tables.entry[SMU10_WMTABLE].table);
197 amdgpu_bo_free_kernel(&priv->smu_tables.entry[SMU10_CLOCKTABLE].handle,
198 &priv->smu_tables.entry[SMU10_CLOCKTABLE].mc_addr,
199 &priv->smu_tables.entry[SMU10_CLOCKTABLE].table);
200 kfree(hwmgr->smu_backend);
201 hwmgr->smu_backend = NULL;
202 }
203
204 return 0;
205}
206
207static int smu10_start_smu(struct pp_hwmgr *hwmgr)
208{
209 struct amdgpu_device *adev = hwmgr->adev;
210
211 smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetSmuVersion);
212 hwmgr->smu_version = smu10_read_arg_from_smc(hwmgr);
213 adev->pm.fw_version = hwmgr->smu_version >> 8;
214
215 if (smu10_verify_smc_interface(hwmgr))
216 return -EINVAL;
217
218 return 0;
219}
220
221static int smu10_smu_init(struct pp_hwmgr *hwmgr)
222{
223 struct smu10_smumgr *priv;
224 int r;
225
226 priv = kzalloc(sizeof(struct smu10_smumgr), GFP_KERNEL);
227
228 if (!priv)
229 return -ENOMEM;
230
231 hwmgr->smu_backend = priv;
232
233 /* allocate space for watermarks table */
234 r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
235 sizeof(Watermarks_t),
236 PAGE_SIZE,
237 AMDGPU_GEM_DOMAIN_VRAM,
238 &priv->smu_tables.entry[SMU10_WMTABLE].handle,
239 &priv->smu_tables.entry[SMU10_WMTABLE].mc_addr,
240 &priv->smu_tables.entry[SMU10_WMTABLE].table);
241
242 if (r)
243 goto err0;
244
245 priv->smu_tables.entry[SMU10_WMTABLE].version = 0x01;
246 priv->smu_tables.entry[SMU10_WMTABLE].size = sizeof(Watermarks_t);
247 priv->smu_tables.entry[SMU10_WMTABLE].table_id = TABLE_WATERMARKS;
248
249 /* allocate space for watermarks table */
250 r = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev,
251 sizeof(DpmClocks_t),
252 PAGE_SIZE,
253 AMDGPU_GEM_DOMAIN_VRAM,
254 &priv->smu_tables.entry[SMU10_CLOCKTABLE].handle,
255 &priv->smu_tables.entry[SMU10_CLOCKTABLE].mc_addr,
256 &priv->smu_tables.entry[SMU10_CLOCKTABLE].table);
257
258 if (r)
259 goto err1;
260
261 priv->smu_tables.entry[SMU10_CLOCKTABLE].version = 0x01;
262 priv->smu_tables.entry[SMU10_CLOCKTABLE].size = sizeof(DpmClocks_t);
263 priv->smu_tables.entry[SMU10_CLOCKTABLE].table_id = TABLE_DPMCLOCKS;
264
265 return 0;
266
267err1:
268 amdgpu_bo_free_kernel(&priv->smu_tables.entry[SMU10_WMTABLE].handle,
269 &priv->smu_tables.entry[SMU10_WMTABLE].mc_addr,
270 &priv->smu_tables.entry[SMU10_WMTABLE].table);
271err0:
272 kfree(priv);
273 return -EINVAL;
274}
275
276static int smu10_smc_table_manager(struct pp_hwmgr *hwmgr, uint8_t *table, uint16_t table_id, bool rw)
277{
278 int ret;
279
280 if (rw)
281 ret = smu10_copy_table_from_smc(hwmgr, table, table_id);
282 else
283 ret = smu10_copy_table_to_smc(hwmgr, table, table_id);
284
285 return ret;
286}
287
288
289const struct pp_smumgr_func smu10_smu_funcs = {
290 .smu_init = &smu10_smu_init,
291 .smu_fini = &smu10_smu_fini,
292 .start_smu = &smu10_start_smu,
293 .request_smu_load_specific_fw = NULL,
294 .send_msg_to_smc = &smu10_send_msg_to_smc,
295 .send_msg_to_smc_with_parameter = &smu10_send_msg_to_smc_with_parameter,
296 .download_pptable_settings = NULL,
297 .upload_pptable_settings = NULL,
298 .get_argument = smu10_read_arg_from_smc,
299 .smc_table_manager = smu10_smc_table_manager,
300};
301
302
303