fe57335152d529fd3039654effee5cb38c8baf91
[muen/linux.git] / drivers / gpu / drm / amd / powerplay / smumgr / iceland_smumgr.c
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 "pp_debug.h"
26 #include <linux/types.h>
27 #include <linux/kernel.h>
28 #include <linux/slab.h>
29 #include <linux/gfp.h>
30
31 #include "smumgr.h"
32 #include "iceland_smumgr.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
42 static int iceland_start_smc(struct pp_hwmgr *hwmgr)
43 {
44         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
45                                   SMC_SYSCON_RESET_CNTL, rst_reg, 0);
46
47         return 0;
48 }
49
50 static void iceland_reset_smc(struct pp_hwmgr *hwmgr)
51 {
52         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
53                                   SMC_SYSCON_RESET_CNTL,
54                                   rst_reg, 1);
55 }
56
57
58 static void iceland_stop_smc_clock(struct pp_hwmgr *hwmgr)
59 {
60         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
61                                   SMC_SYSCON_CLOCK_CNTL_0,
62                                   ck_disable, 1);
63 }
64
65 static void iceland_start_smc_clock(struct pp_hwmgr *hwmgr)
66 {
67         PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
68                                   SMC_SYSCON_CLOCK_CNTL_0,
69                                   ck_disable, 0);
70 }
71
72 static int iceland_smu_start_smc(struct pp_hwmgr *hwmgr)
73 {
74         /* set smc instruct start point at 0x0 */
75         smu7_program_jump_on_start(hwmgr);
76
77         /* enable smc clock */
78         iceland_start_smc_clock(hwmgr);
79
80         /* de-assert reset */
81         iceland_start_smc(hwmgr);
82
83         SMUM_WAIT_INDIRECT_FIELD(hwmgr, SMC_IND, FIRMWARE_FLAGS,
84                                  INTERRUPTS_ENABLED, 1);
85
86         return 0;
87 }
88
89
90 static int iceland_upload_smc_firmware_data(struct pp_hwmgr *hwmgr,
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(hwmgr->device, mmSMC_IND_INDEX_0, start_addr);
100         SMUM_WRITE_FIELD(hwmgr->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(hwmgr->device, mmSMC_IND_DATA_0, data);
105                 src += 4;
106                 byte_count -= 4;
107         }
108
109         SMUM_WRITE_FIELD(hwmgr->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
117 static int iceland_smu_upload_firmware_image(struct pp_hwmgr *hwmgr)
118 {
119         uint32_t val;
120         struct cgs_firmware_info info = {0};
121
122         if (hwmgr == NULL || hwmgr->device == NULL)
123                 return -EINVAL;
124
125         /* load SMC firmware */
126         cgs_get_firmware_info(hwmgr->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         PHM_WAIT_INDIRECT_FIELD_UNEQUAL(hwmgr, SMC_IND,
141                                          RCU_UC_EVENTS, boot_seq_done, 0);
142
143         /* clear firmware interrupt enable flag */
144         val = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC,
145                                     ixSMC_SYSCON_MISC_CNTL);
146         cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
147                                ixSMC_SYSCON_MISC_CNTL, val | 1);
148
149         /* stop smc clock */
150         iceland_stop_smc_clock(hwmgr);
151
152         /* reset smc */
153         iceland_reset_smc(hwmgr);
154         iceland_upload_smc_firmware_data(hwmgr, info.image_size,
155                                 (uint8_t *)info.kptr, ICELAND_SMC_SIZE,
156                                 info.ucode_start_address);
157
158         return 0;
159 }
160
161 static int iceland_request_smu_load_specific_fw(struct pp_hwmgr *hwmgr,
162                                                 uint32_t firmwareType)
163 {
164         return 0;
165 }
166
167 static int iceland_start_smu(struct pp_hwmgr *hwmgr)
168 {
169         int result;
170
171         result = iceland_smu_upload_firmware_image(hwmgr);
172         if (result)
173                 return result;
174         result = iceland_smu_start_smc(hwmgr);
175         if (result)
176                 return result;
177
178         if (!smu7_is_smc_ram_running(hwmgr)) {
179                 pr_info("smu not running, upload firmware again \n");
180                 result = iceland_smu_upload_firmware_image(hwmgr);
181                 if (result)
182                         return result;
183
184                 result = iceland_smu_start_smc(hwmgr);
185                 if (result)
186                         return result;
187         }
188
189         result = smu7_request_smu_load_fw(hwmgr);
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  */
201 static int iceland_smu_init(struct pp_hwmgr *hwmgr)
202 {
203         int i;
204         struct iceland_smumgr *iceland_priv = NULL;
205
206         iceland_priv = kzalloc(sizeof(struct iceland_smumgr), GFP_KERNEL);
207
208         if (iceland_priv == NULL)
209                 return -ENOMEM;
210
211         hwmgr->smu_backend = iceland_priv;
212
213         if (smu7_init(hwmgr))
214                 return -EINVAL;
215
216         for (i = 0; i < SMU71_MAX_LEVELS_GRAPHICS; i++)
217                 iceland_priv->activity_target[i] = 30;
218
219         return 0;
220 }
221
222 const struct pp_smumgr_func iceland_smu_funcs = {
223         .smu_init = &iceland_smu_init,
224         .smu_fini = &smu7_smu_fini,
225         .start_smu = &iceland_start_smu,
226         .check_fw_load_finish = &smu7_check_fw_load_finish,
227         .request_smu_load_fw = &smu7_reload_firmware,
228         .request_smu_load_specific_fw = &iceland_request_smu_load_specific_fw,
229         .send_msg_to_smc = &smu7_send_msg_to_smc,
230         .send_msg_to_smc_with_parameter = &smu7_send_msg_to_smc_with_parameter,
231         .download_pptable_settings = NULL,
232         .upload_pptable_settings = NULL,
233         .get_offsetof = iceland_get_offsetof,
234         .process_firmware_header = iceland_process_firmware_header,
235         .init_smc_table = iceland_init_smc_table,
236         .update_sclk_threshold = iceland_update_sclk_threshold,
237         .thermal_setup_fan_table = iceland_thermal_setup_fan_table,
238         .populate_all_graphic_levels = iceland_populate_all_graphic_levels,
239         .populate_all_memory_levels = iceland_populate_all_memory_levels,
240         .get_mac_definition = iceland_get_mac_definition,
241         .initialize_mc_reg_table = iceland_initialize_mc_reg_table,
242         .is_dpm_running = iceland_is_dpm_running,
243 };
244