2 * Copyright 2016 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
27 #include "rv_smumgr.h"
28 #include "ppatomctrl.h"
30 #include "smu10_driver_if.h"
32 #include "ppatomctrl.h"
34 #include "smu_ucode_xfer_vi.h"
35 #include "smu7_smumgr.h"
37 #define VOLTAGE_SCALE 4
39 #define BUFFER_SIZE 80000
40 #define MAX_STRING_SIZE 15
41 #define BUFFER_SIZETWO 131072
43 #define MP0_Public 0x03800000
44 #define MP0_SRAM 0x03900000
45 #define MP1_Public 0x03b00000
46 #define MP1_SRAM 0x03c00004
48 #define smnMP1_FIRMWARE_FLAGS 0x3010028
51 bool rv_is_smc_ram_running(struct pp_hwmgr *hwmgr)
53 uint32_t mp1_fw_flags, reg;
55 reg = soc15_get_register_offset(NBIF_HWID, 0,
56 mmPCIE_INDEX2_BASE_IDX, mmPCIE_INDEX2);
58 cgs_write_register(hwmgr->device, reg,
59 (MP1_Public | (smnMP1_FIRMWARE_FLAGS & 0xffffffff)));
61 reg = soc15_get_register_offset(NBIF_HWID, 0,
62 mmPCIE_DATA2_BASE_IDX, mmPCIE_DATA2);
64 mp1_fw_flags = cgs_read_register(hwmgr->device, reg);
66 if (mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK)
72 static uint32_t rv_wait_for_response(struct pp_hwmgr *hwmgr)
76 if (!rv_is_smc_ram_running(hwmgr))
79 reg = soc15_get_register_offset(MP1_HWID, 0,
80 mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90);
82 phm_wait_for_register_unequal(hwmgr, reg,
83 0, MP1_C2PMSG_90__CONTENT_MASK);
85 return cgs_read_register(hwmgr->device, reg);
88 int rv_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr,
93 if (!rv_is_smc_ram_running(hwmgr))
96 reg = soc15_get_register_offset(MP1_HWID, 0,
97 mmMP1_SMN_C2PMSG_66_BASE_IDX, mmMP1_SMN_C2PMSG_66);
98 cgs_write_register(hwmgr->device, reg, msg);
103 int rv_read_arg_from_smc(struct pp_hwmgr *hwmgr, uint32_t *arg)
107 reg = soc15_get_register_offset(MP1_HWID, 0,
108 mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82);
110 *arg = cgs_read_register(hwmgr->device, reg);
115 int rv_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg)
119 rv_wait_for_response(hwmgr);
121 reg = soc15_get_register_offset(MP1_HWID, 0,
122 mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90);
123 cgs_write_register(hwmgr->device, reg, 0);
125 rv_send_msg_to_smc_without_waiting(hwmgr, msg);
127 if (rv_wait_for_response(hwmgr) == 0)
128 printk("Failed to send Message %x.\n", msg);
134 int rv_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr,
135 uint16_t msg, uint32_t parameter)
139 rv_wait_for_response(hwmgr);
141 reg = soc15_get_register_offset(MP1_HWID, 0,
142 mmMP1_SMN_C2PMSG_90_BASE_IDX, mmMP1_SMN_C2PMSG_90);
143 cgs_write_register(hwmgr->device, reg, 0);
145 reg = soc15_get_register_offset(MP1_HWID, 0,
146 mmMP1_SMN_C2PMSG_82_BASE_IDX, mmMP1_SMN_C2PMSG_82);
147 cgs_write_register(hwmgr->device, reg, parameter);
149 rv_send_msg_to_smc_without_waiting(hwmgr, msg);
152 if (rv_wait_for_response(hwmgr) == 0)
153 printk("Failed to send Message %x.\n", msg);
158 int rv_copy_table_from_smc(struct pp_hwmgr *hwmgr,
159 uint8_t *table, int16_t table_id)
161 struct rv_smumgr *priv =
162 (struct rv_smumgr *)(hwmgr->smu_backend);
164 PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE,
165 "Invalid SMU Table ID!", return -EINVAL;);
166 PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0,
167 "Invalid SMU Table version!", return -EINVAL;);
168 PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0,
169 "Invalid SMU Table Length!", return -EINVAL;);
170 PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr,
171 PPSMC_MSG_SetDriverDramAddrHigh,
172 priv->smu_tables.entry[table_id].table_addr_high) == 0,
173 "[CopyTableFromSMC] Attempt to Set Dram Addr High Failed!", return -EINVAL;);
174 PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr,
175 PPSMC_MSG_SetDriverDramAddrLow,
176 priv->smu_tables.entry[table_id].table_addr_low) == 0,
177 "[CopyTableFromSMC] Attempt to Set Dram Addr Low Failed!",
179 PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr,
180 PPSMC_MSG_TransferTableSmu2Dram,
181 priv->smu_tables.entry[table_id].table_id) == 0,
182 "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!",
185 memcpy(table, priv->smu_tables.entry[table_id].table,
186 priv->smu_tables.entry[table_id].size);
191 int rv_copy_table_to_smc(struct pp_hwmgr *hwmgr,
192 uint8_t *table, int16_t table_id)
194 struct rv_smumgr *priv =
195 (struct rv_smumgr *)(hwmgr->smu_backend);
197 PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE,
198 "Invalid SMU Table ID!", return -EINVAL;);
199 PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].version != 0,
200 "Invalid SMU Table version!", return -EINVAL;);
201 PP_ASSERT_WITH_CODE(priv->smu_tables.entry[table_id].size != 0,
202 "Invalid SMU Table Length!", return -EINVAL;);
204 memcpy(priv->smu_tables.entry[table_id].table, table,
205 priv->smu_tables.entry[table_id].size);
207 PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr,
208 PPSMC_MSG_SetDriverDramAddrHigh,
209 priv->smu_tables.entry[table_id].table_addr_high) == 0,
210 "[CopyTableToSMC] Attempt to Set Dram Addr High Failed!",
212 PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr,
213 PPSMC_MSG_SetDriverDramAddrLow,
214 priv->smu_tables.entry[table_id].table_addr_low) == 0,
215 "[CopyTableToSMC] Attempt to Set Dram Addr Low Failed!",
217 PP_ASSERT_WITH_CODE(rv_send_msg_to_smc_with_parameter(hwmgr,
218 PPSMC_MSG_TransferTableDram2Smu,
219 priv->smu_tables.entry[table_id].table_id) == 0,
220 "[CopyTableToSMC] Attempt to Transfer Table To SMU Failed!",
226 static int rv_verify_smc_interface(struct pp_hwmgr *hwmgr)
228 uint32_t smc_driver_if_version;
230 PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc(hwmgr,
231 PPSMC_MSG_GetDriverIfVersion),
232 "Attempt to get SMC IF Version Number Failed!",
234 PP_ASSERT_WITH_CODE(!rv_read_arg_from_smc(hwmgr,
235 &smc_driver_if_version),
236 "Attempt to read SMC IF Version Number Failed!",
239 if (smc_driver_if_version != SMU10_DRIVER_IF_VERSION)
245 /* sdma is disabled by default in vbios, need to re-enable in driver */
246 static int rv_smc_enable_sdma(struct pp_hwmgr *hwmgr)
248 PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc(hwmgr,
249 PPSMC_MSG_PowerUpSdma),
250 "Attempt to power up sdma Failed!",
256 static int rv_smc_disable_sdma(struct pp_hwmgr *hwmgr)
258 PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc(hwmgr,
259 PPSMC_MSG_PowerDownSdma),
260 "Attempt to power down sdma Failed!",
266 /* vcn is disabled by default in vbios, need to re-enable in driver */
267 static int rv_smc_enable_vcn(struct pp_hwmgr *hwmgr)
269 PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc_with_parameter(hwmgr,
270 PPSMC_MSG_PowerUpVcn, 0),
271 "Attempt to power up vcn Failed!",
277 static int rv_smc_disable_vcn(struct pp_hwmgr *hwmgr)
279 PP_ASSERT_WITH_CODE(!rv_send_msg_to_smc_with_parameter(hwmgr,
280 PPSMC_MSG_PowerDownVcn, 0),
281 "Attempt to power down vcn Failed!",
287 static int rv_smu_fini(struct pp_hwmgr *hwmgr)
289 struct rv_smumgr *priv =
290 (struct rv_smumgr *)(hwmgr->smu_backend);
293 rv_smc_disable_sdma(hwmgr);
294 rv_smc_disable_vcn(hwmgr);
295 cgs_free_gpu_mem(hwmgr->device,
296 priv->smu_tables.entry[WMTABLE].handle);
297 cgs_free_gpu_mem(hwmgr->device,
298 priv->smu_tables.entry[CLOCKTABLE].handle);
299 kfree(hwmgr->smu_backend);
300 hwmgr->smu_backend = NULL;
306 static int rv_start_smu(struct pp_hwmgr *hwmgr)
308 if (rv_verify_smc_interface(hwmgr))
310 if (rv_smc_enable_sdma(hwmgr))
312 if (rv_smc_enable_vcn(hwmgr))
318 static int rv_smu_init(struct pp_hwmgr *hwmgr)
320 struct rv_smumgr *priv;
323 unsigned long handle;
325 priv = kzalloc(sizeof(struct rv_smumgr), GFP_KERNEL);
330 hwmgr->smu_backend = priv;
332 /* allocate space for watermarks table */
333 smu_allocate_memory(hwmgr->device,
334 sizeof(Watermarks_t),
335 CGS_GPU_MEM_TYPE__GART_CACHEABLE,
341 PP_ASSERT_WITH_CODE(kaddr,
342 "[rv_smu_init] Out of memory for wmtable.",
343 kfree(hwmgr->smu_backend);
344 hwmgr->smu_backend = NULL;
347 priv->smu_tables.entry[WMTABLE].version = 0x01;
348 priv->smu_tables.entry[WMTABLE].size = sizeof(Watermarks_t);
349 priv->smu_tables.entry[WMTABLE].table_id = TABLE_WATERMARKS;
350 priv->smu_tables.entry[WMTABLE].table_addr_high =
351 smu_upper_32_bits(mc_addr);
352 priv->smu_tables.entry[WMTABLE].table_addr_low =
353 smu_lower_32_bits(mc_addr);
354 priv->smu_tables.entry[WMTABLE].table = kaddr;
355 priv->smu_tables.entry[WMTABLE].handle = handle;
357 /* allocate space for watermarks table */
358 smu_allocate_memory(hwmgr->device,
360 CGS_GPU_MEM_TYPE__GART_CACHEABLE,
366 PP_ASSERT_WITH_CODE(kaddr,
367 "[rv_smu_init] Out of memory for CLOCKTABLE.",
368 cgs_free_gpu_mem(hwmgr->device,
369 (cgs_handle_t)priv->smu_tables.entry[WMTABLE].handle);
370 kfree(hwmgr->smu_backend);
371 hwmgr->smu_backend = NULL;
374 priv->smu_tables.entry[CLOCKTABLE].version = 0x01;
375 priv->smu_tables.entry[CLOCKTABLE].size = sizeof(DpmClocks_t);
376 priv->smu_tables.entry[CLOCKTABLE].table_id = TABLE_DPMCLOCKS;
377 priv->smu_tables.entry[CLOCKTABLE].table_addr_high =
378 smu_upper_32_bits(mc_addr);
379 priv->smu_tables.entry[CLOCKTABLE].table_addr_low =
380 smu_lower_32_bits(mc_addr);
381 priv->smu_tables.entry[CLOCKTABLE].table = kaddr;
382 priv->smu_tables.entry[CLOCKTABLE].handle = handle;
387 const struct pp_smumgr_func rv_smu_funcs = {
388 .smu_init = &rv_smu_init,
389 .smu_fini = &rv_smu_fini,
390 .start_smu = &rv_start_smu,
391 .request_smu_load_specific_fw = NULL,
392 .send_msg_to_smc = &rv_send_msg_to_smc,
393 .send_msg_to_smc_with_parameter = &rv_send_msg_to_smc_with_parameter,
394 .download_pptable_settings = NULL,
395 .upload_pptable_settings = NULL,