Merge tag 'mmc-v4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
[cascardo/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 <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
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
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
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
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
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
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
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
161 static int iceland_request_smu_load_specific_fw(struct pp_smumgr *smumgr,
162                                                 uint32_t firmwareType)
163 {
164         return 0;
165 }
166
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  */
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
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 }