]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
drm/amd/display: Add debug trace for dmcub FW autoload.
[linux.git] / drivers / gpu / drm / amd / display / dmub / src / dmub_srv.c
1 /*
2  * Copyright 2019 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  * Authors: AMD
23  *
24  */
25
26 #include "../inc/dmub_srv.h"
27 #include "dmub_dcn20.h"
28 #include "dmub_dcn21.h"
29 #include "dmub_trace_buffer.h"
30 #include "os_types.h"
31 /*
32  * Note: the DMUB service is standalone. No additional headers should be
33  * added below or above this line unless they reside within the DMUB
34  * folder.
35  */
36
37 /* Alignment for framebuffer memory. */
38 #define DMUB_FB_ALIGNMENT (1024 * 1024)
39
40 /* Stack size. */
41 #define DMUB_STACK_SIZE (128 * 1024)
42
43 /* Context size. */
44 #define DMUB_CONTEXT_SIZE (512 * 1024)
45
46 /* Mailbox size */
47 #define DMUB_MAILBOX_SIZE (DMUB_RB_SIZE)
48
49
50 /* Number of windows in use. */
51 #define DMUB_NUM_WINDOWS (DMUB_WINDOW_5_TRACEBUFF + 1)
52 /* Base addresses. */
53
54 #define DMUB_CW0_BASE (0x60000000)
55 #define DMUB_CW1_BASE (0x61000000)
56 #define DMUB_CW3_BASE (0x63000000)
57 #define DMUB_CW5_BASE (0x65000000)
58
59 static inline uint32_t dmub_align(uint32_t val, uint32_t factor)
60 {
61         return (val + factor - 1) / factor * factor;
62 }
63
64 static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
65 {
66         struct dmub_srv_hw_funcs *funcs = &dmub->hw_funcs;
67
68         switch (asic) {
69         case DMUB_ASIC_DCN20:
70         case DMUB_ASIC_DCN21:
71                 funcs->reset = dmub_dcn20_reset;
72                 funcs->reset_release = dmub_dcn20_reset_release;
73                 funcs->backdoor_load = dmub_dcn20_backdoor_load;
74                 funcs->setup_windows = dmub_dcn20_setup_windows;
75                 funcs->setup_mailbox = dmub_dcn20_setup_mailbox;
76                 funcs->get_inbox1_rptr = dmub_dcn20_get_inbox1_rptr;
77                 funcs->set_inbox1_wptr = dmub_dcn20_set_inbox1_wptr;
78                 funcs->is_supported = dmub_dcn20_is_supported;
79                 funcs->is_phy_init = dmub_dcn20_is_phy_init;
80                 funcs->is_hw_init = dmub_dcn20_is_hw_init;
81
82                 if (asic == DMUB_ASIC_DCN21) {
83                         funcs->backdoor_load = dmub_dcn21_backdoor_load;
84                         funcs->setup_windows = dmub_dcn21_setup_windows;
85                         funcs->is_auto_load_done = dmub_dcn21_is_auto_load_done;
86                 }
87                 break;
88
89         default:
90                 return false;
91         }
92
93         return true;
94 }
95
96 enum dmub_status dmub_srv_create(struct dmub_srv *dmub,
97                                  const struct dmub_srv_create_params *params)
98 {
99         enum dmub_status status = DMUB_STATUS_OK;
100
101         dmub_memset(dmub, 0, sizeof(*dmub));
102
103         dmub->funcs = params->funcs;
104         dmub->user_ctx = params->user_ctx;
105         dmub->asic = params->asic;
106         dmub->is_virtual = params->is_virtual;
107
108         /* Setup asic dependent hardware funcs. */
109         if (!dmub_srv_hw_setup(dmub, params->asic)) {
110                 status = DMUB_STATUS_INVALID;
111                 goto cleanup;
112         }
113
114         /* Override (some) hardware funcs based on user params. */
115         if (params->hw_funcs) {
116                 if (params->hw_funcs->get_inbox1_rptr)
117                         dmub->hw_funcs.get_inbox1_rptr =
118                                 params->hw_funcs->get_inbox1_rptr;
119
120                 if (params->hw_funcs->set_inbox1_wptr)
121                         dmub->hw_funcs.set_inbox1_wptr =
122                                 params->hw_funcs->set_inbox1_wptr;
123
124                 if (params->hw_funcs->is_supported)
125                         dmub->hw_funcs.is_supported =
126                                 params->hw_funcs->is_supported;
127         }
128
129         /* Sanity checks for required hw func pointers. */
130         if (!dmub->hw_funcs.get_inbox1_rptr ||
131             !dmub->hw_funcs.set_inbox1_wptr) {
132                 status = DMUB_STATUS_INVALID;
133                 goto cleanup;
134         }
135
136 cleanup:
137         if (status == DMUB_STATUS_OK)
138                 dmub->sw_init = true;
139         else
140                 dmub_srv_destroy(dmub);
141
142         return status;
143 }
144
145 void dmub_srv_destroy(struct dmub_srv *dmub)
146 {
147         dmub_memset(dmub, 0, sizeof(*dmub));
148 }
149
150 enum dmub_status
151 dmub_srv_calc_region_info(struct dmub_srv *dmub,
152                           const struct dmub_srv_region_params *params,
153                           struct dmub_srv_region_info *out)
154 {
155         struct dmub_region *inst = &out->regions[DMUB_WINDOW_0_INST_CONST];
156         struct dmub_region *stack = &out->regions[DMUB_WINDOW_1_STACK];
157         struct dmub_region *data = &out->regions[DMUB_WINDOW_2_BSS_DATA];
158         struct dmub_region *bios = &out->regions[DMUB_WINDOW_3_VBIOS];
159         struct dmub_region *mail = &out->regions[DMUB_WINDOW_4_MAILBOX];
160         struct dmub_region *trace_buff = &out->regions[DMUB_WINDOW_5_TRACEBUFF];
161
162         if (!dmub->sw_init)
163                 return DMUB_STATUS_INVALID;
164
165         memset(out, 0, sizeof(*out));
166
167         out->num_regions = DMUB_NUM_WINDOWS;
168
169         inst->base = 0x0;
170         inst->top = inst->base + params->inst_const_size;
171
172         data->base = dmub_align(inst->top, 256);
173         data->top = data->base + params->bss_data_size;
174
175         stack->base = dmub_align(data->top, 256);
176         stack->top = stack->base + DMUB_STACK_SIZE + DMUB_CONTEXT_SIZE;
177
178         bios->base = dmub_align(stack->top, 256);
179         bios->top = bios->base + params->vbios_size;
180
181         mail->base = dmub_align(bios->top, 256);
182         mail->top = mail->base + DMUB_MAILBOX_SIZE;
183
184         trace_buff->base = dmub_align(mail->top, 256);
185         trace_buff->top = trace_buff->base + TRACE_BUF_SIZE;
186
187         out->fb_size = dmub_align(trace_buff->top, 4096);
188
189         return DMUB_STATUS_OK;
190 }
191
192 enum dmub_status dmub_srv_calc_fb_info(struct dmub_srv *dmub,
193                                        const struct dmub_srv_fb_params *params,
194                                        struct dmub_srv_fb_info *out)
195 {
196         uint8_t *cpu_base;
197         uint64_t gpu_base;
198         uint32_t i;
199
200         if (!dmub->sw_init)
201                 return DMUB_STATUS_INVALID;
202
203         memset(out, 0, sizeof(*out));
204
205         if (params->region_info->num_regions != DMUB_NUM_WINDOWS)
206                 return DMUB_STATUS_INVALID;
207
208         cpu_base = (uint8_t *)params->cpu_addr;
209         gpu_base = params->gpu_addr;
210
211         for (i = 0; i < DMUB_NUM_WINDOWS; ++i) {
212                 const struct dmub_region *reg =
213                         &params->region_info->regions[i];
214
215                 out->fb[i].cpu_addr = cpu_base + reg->base;
216                 out->fb[i].gpu_addr = gpu_base + reg->base;
217                 out->fb[i].size = reg->top - reg->base;
218         }
219
220         out->num_fb = DMUB_NUM_WINDOWS;
221
222         return DMUB_STATUS_OK;
223 }
224
225 enum dmub_status dmub_srv_has_hw_support(struct dmub_srv *dmub,
226                                          bool *is_supported)
227 {
228         *is_supported = false;
229
230         if (!dmub->sw_init)
231                 return DMUB_STATUS_INVALID;
232
233         if (dmub->hw_funcs.is_supported)
234                 *is_supported = dmub->hw_funcs.is_supported(dmub);
235
236         return DMUB_STATUS_OK;
237 }
238
239 enum dmub_status dmub_srv_is_hw_init(struct dmub_srv *dmub, bool *is_hw_init)
240 {
241         *is_hw_init = false;
242
243         if (!dmub->sw_init)
244                 return DMUB_STATUS_INVALID;
245
246         if (dmub->hw_funcs.is_hw_init)
247                 *is_hw_init = dmub->hw_funcs.is_hw_init(dmub);
248
249         return DMUB_STATUS_OK;
250 }
251
252 enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub,
253                                   const struct dmub_srv_hw_params *params)
254 {
255         struct dmub_fb *inst_fb = params->fb[DMUB_WINDOW_0_INST_CONST];
256         struct dmub_fb *stack_fb = params->fb[DMUB_WINDOW_1_STACK];
257         struct dmub_fb *data_fb = params->fb[DMUB_WINDOW_2_BSS_DATA];
258         struct dmub_fb *bios_fb = params->fb[DMUB_WINDOW_3_VBIOS];
259         struct dmub_fb *mail_fb = params->fb[DMUB_WINDOW_4_MAILBOX];
260         struct dmub_fb *tracebuff_fb = params->fb[DMUB_WINDOW_5_TRACEBUFF];
261
262         struct dmub_rb_init_params rb_params;
263         struct dmub_window cw0, cw1, cw2, cw3, cw4, cw5;
264         struct dmub_region inbox1;
265
266         if (!dmub->sw_init)
267                 return DMUB_STATUS_INVALID;
268
269         dmub->fb_base = params->fb_base;
270         dmub->fb_offset = params->fb_offset;
271         dmub->psp_version = params->psp_version;
272
273         if (inst_fb && data_fb) {
274                 cw0.offset.quad_part = inst_fb->gpu_addr;
275                 cw0.region.base = DMUB_CW0_BASE;
276                 cw0.region.top = cw0.region.base + inst_fb->size - 1;
277
278                 cw1.offset.quad_part = stack_fb->gpu_addr;
279                 cw1.region.base = DMUB_CW1_BASE;
280                 cw1.region.top = cw1.region.base + stack_fb->size - 1;
281
282                 if (params->load_inst_const && dmub->hw_funcs.backdoor_load)
283                         dmub->hw_funcs.backdoor_load(dmub, &cw0, &cw1);
284         }
285
286         if (dmub->hw_funcs.reset)
287                 dmub->hw_funcs.reset(dmub);
288
289         if (inst_fb && data_fb && bios_fb && mail_fb) {
290                 cw2.offset.quad_part = data_fb->gpu_addr;
291                 cw2.region.base = DMUB_CW0_BASE + inst_fb->size;
292                 cw2.region.top = cw2.region.base + data_fb->size;
293
294                 cw3.offset.quad_part = bios_fb->gpu_addr;
295                 cw3.region.base = DMUB_CW3_BASE;
296                 cw3.region.top = cw3.region.base + bios_fb->size;
297
298                 cw4.offset.quad_part = mail_fb->gpu_addr;
299                 cw4.region.base = cw3.region.top + 1;
300                 cw4.region.top = cw4.region.base + mail_fb->size;
301
302                 inbox1.base = cw4.region.base;
303                 inbox1.top = cw4.region.top;
304
305                 cw5.offset.quad_part = tracebuff_fb->gpu_addr;
306                 cw5.region.base = DMUB_CW5_BASE;
307                 cw5.region.top = cw5.region.base + tracebuff_fb->size;
308
309                 if (dmub->hw_funcs.setup_windows)
310                         dmub->hw_funcs.setup_windows(dmub, &cw2, &cw3, &cw4, &cw5);
311
312                 if (dmub->hw_funcs.setup_mailbox)
313                         dmub->hw_funcs.setup_mailbox(dmub, &inbox1);
314         }
315
316         if (mail_fb) {
317                 dmub_memset(&rb_params, 0, sizeof(rb_params));
318                 rb_params.ctx = dmub;
319                 rb_params.base_address = mail_fb->cpu_addr;
320                 rb_params.capacity = DMUB_RB_SIZE;
321
322                 dmub_rb_init(&dmub->inbox1_rb, &rb_params);
323         }
324
325         if (dmub->hw_funcs.reset_release)
326                 dmub->hw_funcs.reset_release(dmub);
327
328         dmub->hw_init = true;
329
330         return DMUB_STATUS_OK;
331 }
332
333 enum dmub_status dmub_srv_cmd_queue(struct dmub_srv *dmub,
334                                     const struct dmub_cmd_header *cmd)
335 {
336         if (!dmub->hw_init)
337                 return DMUB_STATUS_INVALID;
338
339         if (dmub_rb_push_front(&dmub->inbox1_rb, cmd))
340                 return DMUB_STATUS_OK;
341
342         return DMUB_STATUS_QUEUE_FULL;
343 }
344
345 enum dmub_status dmub_srv_cmd_execute(struct dmub_srv *dmub)
346 {
347         if (!dmub->hw_init)
348                 return DMUB_STATUS_INVALID;
349
350         dmub->hw_funcs.set_inbox1_wptr(dmub, dmub->inbox1_rb.wrpt);
351         return DMUB_STATUS_OK;
352 }
353
354 enum dmub_status dmub_srv_cmd_submit(struct dmub_srv *dmub,
355                                      const struct dmub_cmd_header *cmd,
356                                      uint32_t timeout_us)
357 {
358         uint32_t i = 0;
359
360         if (!dmub->hw_init)
361                 return DMUB_STATUS_INVALID;
362
363         for (i = 0; i <= timeout_us; ++i) {
364                 dmub->inbox1_rb.rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
365                 if (dmub_rb_push_front(&dmub->inbox1_rb, cmd)) {
366                         dmub->hw_funcs.set_inbox1_wptr(dmub,
367                                                        dmub->inbox1_rb.wrpt);
368                         return DMUB_STATUS_OK;
369                 }
370
371                 udelay(1);
372         }
373
374         return DMUB_STATUS_TIMEOUT;
375 }
376
377 enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub,
378                                              uint32_t timeout_us)
379 {
380         uint32_t i;
381
382         if (!dmub->hw_init || !dmub->hw_funcs.is_auto_load_done)
383                 return DMUB_STATUS_INVALID;
384
385         for (i = 0; i <= timeout_us; i += 100) {
386                 if (dmub->hw_funcs.is_auto_load_done(dmub))
387                         return DMUB_STATUS_OK;
388
389                 udelay(100);
390         }
391
392         return DMUB_STATUS_TIMEOUT;
393 }
394
395 enum dmub_status dmub_srv_wait_for_phy_init(struct dmub_srv *dmub,
396                                             uint32_t timeout_us)
397 {
398         uint32_t i = 0;
399
400         if (!dmub->hw_init || !dmub->hw_funcs.is_phy_init)
401                 return DMUB_STATUS_INVALID;
402
403 /*      for (i = 0; i <= timeout_us; i += 10) {
404                 if (dmub->hw_funcs.is_phy_init(dmub))
405                         return DMUB_STATUS_OK;
406
407                 udelay(10);
408         }*/
409         while (!dmub->hw_funcs.is_phy_init(dmub)) {
410                 ASSERT(i <= timeout_us);
411                 i += 10;
412                 udelay(10);
413         }
414
415         return DMUB_STATUS_OK;
416 }
417
418 enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub,
419                                         uint32_t timeout_us)
420 {
421         uint32_t i;
422
423         if (!dmub->hw_init)
424                 return DMUB_STATUS_INVALID;
425
426         for (i = 0; i <= timeout_us; ++i) {
427                 dmub->inbox1_rb.rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
428                 if (dmub_rb_empty(&dmub->inbox1_rb))
429                         return DMUB_STATUS_OK;
430
431                 udelay(1);
432         }
433
434         return DMUB_STATUS_TIMEOUT;
435 }