drm/msm: bump kernel api version for explicit fencing
[cascardo/linux.git] / drivers / gpu / drm / amd / powerplay / smumgr / smumgr.c
1 /*
2  * Copyright 2015 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 #include <linux/types.h>
24 #include <linux/kernel.h>
25 #include <linux/slab.h>
26 #include <drm/amdgpu_drm.h>
27 #include "pp_instance.h"
28 #include "smumgr.h"
29 #include "cgs_common.h"
30 #include "linux/delay.h"
31 #include "cz_smumgr.h"
32 #include "tonga_smumgr.h"
33 #include "iceland_smumgr.h"
34 #include "fiji_smumgr.h"
35 #include "polaris10_smumgr.h"
36
37 int smum_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
38 {
39         struct pp_smumgr *smumgr;
40
41         if ((handle == NULL) || (pp_init == NULL))
42                 return -EINVAL;
43
44         smumgr = kzalloc(sizeof(struct pp_smumgr), GFP_KERNEL);
45         if (smumgr == NULL)
46                 return -ENOMEM;
47
48         smumgr->device = pp_init->device;
49         smumgr->chip_family = pp_init->chip_family;
50         smumgr->chip_id = pp_init->chip_id;
51         smumgr->hw_revision = pp_init->rev_id;
52         smumgr->usec_timeout = AMD_MAX_USEC_TIMEOUT;
53         smumgr->reload_fw = 1;
54         handle->smu_mgr = smumgr;
55
56         switch (smumgr->chip_family) {
57         case AMDGPU_FAMILY_CZ:
58                 cz_smum_init(smumgr);
59                 break;
60         case AMDGPU_FAMILY_VI:
61                 switch (smumgr->chip_id) {
62                 case CHIP_TOPAZ:
63                         iceland_smum_init(smumgr);
64                         break;
65                 case CHIP_TONGA:
66                         tonga_smum_init(smumgr);
67                         break;
68                 case CHIP_FIJI:
69                         fiji_smum_init(smumgr);
70                         break;
71                 case CHIP_POLARIS11:
72                 case CHIP_POLARIS10:
73                         polaris10_smum_init(smumgr);
74                         break;
75                 default:
76                         return -EINVAL;
77                 }
78                 break;
79         default:
80                 kfree(smumgr);
81                 return -EINVAL;
82         }
83
84         return 0;
85 }
86
87 int smum_fini(struct pp_smumgr *smumgr)
88 {
89         kfree(smumgr->device);
90         kfree(smumgr);
91         return 0;
92 }
93
94 int smum_get_argument(struct pp_smumgr *smumgr)
95 {
96         if (NULL != smumgr->smumgr_funcs->get_argument)
97                 return smumgr->smumgr_funcs->get_argument(smumgr);
98
99         return 0;
100 }
101
102 int smum_download_powerplay_table(struct pp_smumgr *smumgr,
103                                                                 void **table)
104 {
105         if (NULL != smumgr->smumgr_funcs->download_pptable_settings)
106                 return smumgr->smumgr_funcs->download_pptable_settings(smumgr,
107                                                                         table);
108
109         return 0;
110 }
111
112 int smum_upload_powerplay_table(struct pp_smumgr *smumgr)
113 {
114         if (NULL != smumgr->smumgr_funcs->upload_pptable_settings)
115                 return smumgr->smumgr_funcs->upload_pptable_settings(smumgr);
116
117         return 0;
118 }
119
120 int smum_send_msg_to_smc(struct pp_smumgr *smumgr, uint16_t msg)
121 {
122         if (smumgr == NULL || smumgr->smumgr_funcs->send_msg_to_smc == NULL)
123                 return -EINVAL;
124
125         return smumgr->smumgr_funcs->send_msg_to_smc(smumgr, msg);
126 }
127
128 int smum_send_msg_to_smc_with_parameter(struct pp_smumgr *smumgr,
129                                         uint16_t msg, uint32_t parameter)
130 {
131         if (smumgr == NULL ||
132                 smumgr->smumgr_funcs->send_msg_to_smc_with_parameter == NULL)
133                 return -EINVAL;
134         return smumgr->smumgr_funcs->send_msg_to_smc_with_parameter(
135                                                 smumgr, msg, parameter);
136 }
137
138 /*
139  * Returns once the part of the register indicated by the mask has
140  * reached the given value.
141  */
142 int smum_wait_on_register(struct pp_smumgr *smumgr,
143                                 uint32_t index,
144                                 uint32_t value, uint32_t mask)
145 {
146         uint32_t i;
147         uint32_t cur_value;
148
149         if (smumgr == NULL || smumgr->device == NULL)
150                 return -EINVAL;
151
152         for (i = 0; i < smumgr->usec_timeout; i++) {
153                 cur_value = cgs_read_register(smumgr->device, index);
154                 if ((cur_value & mask) == (value & mask))
155                         break;
156                 udelay(1);
157         }
158
159         /* timeout means wrong logic*/
160         if (i == smumgr->usec_timeout)
161                 return -1;
162
163         return 0;
164 }
165
166 int smum_wait_for_register_unequal(struct pp_smumgr *smumgr,
167                                         uint32_t index,
168                                         uint32_t value, uint32_t mask)
169 {
170         uint32_t i;
171         uint32_t cur_value;
172
173         if (smumgr == NULL)
174                 return -EINVAL;
175
176         for (i = 0; i < smumgr->usec_timeout; i++) {
177                 cur_value = cgs_read_register(smumgr->device,
178                                                                         index);
179                 if ((cur_value & mask) != (value & mask))
180                         break;
181                 udelay(1);
182         }
183
184         /* timeout means wrong logic */
185         if (i == smumgr->usec_timeout)
186                 return -1;
187
188         return 0;
189 }
190
191
192 /*
193  * Returns once the part of the register indicated by the mask
194  * has reached the given value.The indirect space is described by
195  * giving the memory-mapped index of the indirect index register.
196  */
197 int smum_wait_on_indirect_register(struct pp_smumgr *smumgr,
198                                         uint32_t indirect_port,
199                                         uint32_t index,
200                                         uint32_t value,
201                                         uint32_t mask)
202 {
203         if (smumgr == NULL || smumgr->device == NULL)
204                 return -EINVAL;
205
206         cgs_write_register(smumgr->device, indirect_port, index);
207         return smum_wait_on_register(smumgr, indirect_port + 1,
208                                                 mask, value);
209 }
210
211 void smum_wait_for_indirect_register_unequal(
212                                                 struct pp_smumgr *smumgr,
213                                                 uint32_t indirect_port,
214                                                 uint32_t index,
215                                                 uint32_t value,
216                                                 uint32_t mask)
217 {
218         if (smumgr == NULL || smumgr->device == NULL)
219                 return;
220         cgs_write_register(smumgr->device, indirect_port, index);
221         smum_wait_for_register_unequal(smumgr, indirect_port + 1,
222                                                 value, mask);
223 }
224
225 int smu_allocate_memory(void *device, uint32_t size,
226                          enum cgs_gpu_mem_type type,
227                          uint32_t byte_align, uint64_t *mc_addr,
228                          void **kptr, void *handle)
229 {
230         int ret = 0;
231         cgs_handle_t cgs_handle;
232
233         if (device == NULL || handle == NULL ||
234             mc_addr == NULL || kptr == NULL)
235                 return -EINVAL;
236
237         ret = cgs_alloc_gpu_mem(device, type, size, byte_align,
238                                 0, 0, (cgs_handle_t *)handle);
239         if (ret)
240                 return -ENOMEM;
241
242         cgs_handle = *(cgs_handle_t *)handle;
243
244         ret = cgs_gmap_gpu_mem(device, cgs_handle, mc_addr);
245         if (ret)
246                 goto error_gmap;
247
248         ret = cgs_kmap_gpu_mem(device, cgs_handle, kptr);
249         if (ret)
250                 goto error_kmap;
251
252         return 0;
253
254 error_kmap:
255         cgs_gunmap_gpu_mem(device, cgs_handle);
256
257 error_gmap:
258         cgs_free_gpu_mem(device, cgs_handle);
259         return ret;
260 }
261
262 int smu_free_memory(void *device, void *handle)
263 {
264         cgs_handle_t cgs_handle = (cgs_handle_t)handle;
265
266         if (device == NULL || handle == NULL)
267                 return -EINVAL;
268
269         cgs_kunmap_gpu_mem(device, cgs_handle);
270         cgs_gunmap_gpu_mem(device, cgs_handle);
271         cgs_free_gpu_mem(device, cgs_handle);
272
273         return 0;
274 }