Commit | Line | Data |
---|---|---|
7c008829 NK |
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 | ||
cdca3f21 | 26 | #include "../dmub_srv.h" |
7c008829 NK |
27 | #include "dmub_dcn20.h" |
28 | #include "dmub_dcn21.h" | |
1f0674fd | 29 | #include "dmub_fw_meta.h" |
b9e9f11c | 30 | #include "os_types.h" |
7c008829 NK |
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 | ||
1f0674fd | 49 | /* Default state size if meta is absent. */ |
891f016d | 50 | #define DMUB_FW_STATE_SIZE (64 * 1024) |
1f0674fd NK |
51 | |
52 | /* Default tracebuffer size if meta is absent. */ | |
891f016d | 53 | #define DMUB_TRACE_BUFFER_SIZE (64 * 1024) |
7c008829 | 54 | |
2277f01d WW |
55 | /* Default scratch mem size. */ |
56 | #define DMUB_SCRATCH_MEM_SIZE (256) | |
57 | ||
7c008829 | 58 | /* Number of windows in use. */ |
2277f01d | 59 | #define DMUB_NUM_WINDOWS (DMUB_WINDOW_TOTAL) |
7c008829 NK |
60 | /* Base addresses. */ |
61 | ||
62 | #define DMUB_CW0_BASE (0x60000000) | |
63 | #define DMUB_CW1_BASE (0x61000000) | |
b9e9f11c | 64 | #define DMUB_CW3_BASE (0x63000000) |
562c805f | 65 | #define DMUB_CW4_BASE (0x64000000) |
7c008829 | 66 | #define DMUB_CW5_BASE (0x65000000) |
2f39835c | 67 | #define DMUB_CW6_BASE (0x66000000) |
7c008829 NK |
68 | |
69 | static inline uint32_t dmub_align(uint32_t val, uint32_t factor) | |
70 | { | |
71 | return (val + factor - 1) / factor * factor; | |
72 | } | |
73 | ||
c5d5b0ec | 74 | void dmub_flush_buffer_mem(const struct dmub_fb *fb) |
dee5d542 NK |
75 | { |
76 | const uint8_t *base = (const uint8_t *)fb->cpu_addr; | |
77 | uint8_t buf[64]; | |
78 | uint32_t pos, end; | |
79 | ||
80 | /** | |
81 | * Read 64-byte chunks since we don't want to store a | |
82 | * large temporary buffer for this purpose. | |
83 | */ | |
84 | end = fb->size / sizeof(buf) * sizeof(buf); | |
85 | ||
86 | for (pos = 0; pos < end; pos += sizeof(buf)) | |
87 | dmub_memcpy(buf, base + pos, sizeof(buf)); | |
88 | ||
89 | /* Read anything leftover into the buffer. */ | |
90 | if (end < fb->size) | |
91 | dmub_memcpy(buf, base + pos, fb->size - end); | |
92 | } | |
93 | ||
1f0674fd | 94 | static const struct dmub_fw_meta_info * |
a576b345 | 95 | dmub_get_fw_meta_info(const struct dmub_srv_region_params *params) |
1f0674fd NK |
96 | { |
97 | const union dmub_fw_meta *meta; | |
a576b345 NK |
98 | const uint8_t *blob = NULL; |
99 | uint32_t blob_size = 0; | |
d5617541 | 100 | uint32_t meta_offset = 0; |
a576b345 | 101 | |
08a512d4 | 102 | if (params->fw_bss_data && params->bss_data_size) { |
a576b345 NK |
103 | /* Legacy metadata region. */ |
104 | blob = params->fw_bss_data; | |
105 | blob_size = params->bss_data_size; | |
d5617541 | 106 | meta_offset = DMUB_FW_META_OFFSET; |
08a512d4 | 107 | } else if (params->fw_inst_const && params->inst_const_size) { |
a576b345 NK |
108 | /* Combined metadata region. */ |
109 | blob = params->fw_inst_const; | |
110 | blob_size = params->inst_const_size; | |
d5617541 | 111 | meta_offset = 0; |
a576b345 | 112 | } |
1f0674fd | 113 | |
a576b345 | 114 | if (!blob || !blob_size) |
1f0674fd NK |
115 | return NULL; |
116 | ||
d5617541 | 117 | if (blob_size < sizeof(union dmub_fw_meta) + meta_offset) |
1f0674fd NK |
118 | return NULL; |
119 | ||
d5617541 | 120 | meta = (const union dmub_fw_meta *)(blob + blob_size - meta_offset - |
1f0674fd NK |
121 | sizeof(union dmub_fw_meta)); |
122 | ||
123 | if (meta->info.magic_value != DMUB_FW_META_MAGIC) | |
124 | return NULL; | |
125 | ||
126 | return &meta->info; | |
127 | } | |
128 | ||
7c008829 NK |
129 | static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic) |
130 | { | |
131 | struct dmub_srv_hw_funcs *funcs = &dmub->hw_funcs; | |
132 | ||
133 | switch (asic) { | |
134 | case DMUB_ASIC_DCN20: | |
135 | case DMUB_ASIC_DCN21: | |
01c229d9 NK |
136 | dmub->regs = &dmub_srv_dcn20_regs; |
137 | ||
7c008829 NK |
138 | funcs->reset = dmub_dcn20_reset; |
139 | funcs->reset_release = dmub_dcn20_reset_release; | |
140 | funcs->backdoor_load = dmub_dcn20_backdoor_load; | |
141 | funcs->setup_windows = dmub_dcn20_setup_windows; | |
142 | funcs->setup_mailbox = dmub_dcn20_setup_mailbox; | |
143 | funcs->get_inbox1_rptr = dmub_dcn20_get_inbox1_rptr; | |
144 | funcs->set_inbox1_wptr = dmub_dcn20_set_inbox1_wptr; | |
145 | funcs->is_supported = dmub_dcn20_is_supported; | |
c09eeee4 | 146 | funcs->is_hw_init = dmub_dcn20_is_hw_init; |
fbbd3f8f NK |
147 | funcs->set_gpint = dmub_dcn20_set_gpint; |
148 | funcs->is_gpint_acked = dmub_dcn20_is_gpint_acked; | |
149 | funcs->get_gpint_response = dmub_dcn20_get_gpint_response; | |
7c008829 NK |
150 | |
151 | if (asic == DMUB_ASIC_DCN21) { | |
01c229d9 NK |
152 | dmub->regs = &dmub_srv_dcn21_regs; |
153 | ||
7c008829 | 154 | funcs->is_auto_load_done = dmub_dcn21_is_auto_load_done; |
3c465370 | 155 | funcs->is_phy_init = dmub_dcn21_is_phy_init; |
7c008829 NK |
156 | } |
157 | break; | |
158 | ||
159 | default: | |
160 | return false; | |
161 | } | |
162 | ||
163 | return true; | |
164 | } | |
165 | ||
166 | enum dmub_status dmub_srv_create(struct dmub_srv *dmub, | |
167 | const struct dmub_srv_create_params *params) | |
168 | { | |
169 | enum dmub_status status = DMUB_STATUS_OK; | |
170 | ||
171 | dmub_memset(dmub, 0, sizeof(*dmub)); | |
172 | ||
173 | dmub->funcs = params->funcs; | |
174 | dmub->user_ctx = params->user_ctx; | |
175 | dmub->asic = params->asic; | |
455802c7 | 176 | dmub->fw_version = params->fw_version; |
7c008829 NK |
177 | dmub->is_virtual = params->is_virtual; |
178 | ||
179 | /* Setup asic dependent hardware funcs. */ | |
180 | if (!dmub_srv_hw_setup(dmub, params->asic)) { | |
181 | status = DMUB_STATUS_INVALID; | |
182 | goto cleanup; | |
183 | } | |
184 | ||
185 | /* Override (some) hardware funcs based on user params. */ | |
186 | if (params->hw_funcs) { | |
187 | if (params->hw_funcs->get_inbox1_rptr) | |
188 | dmub->hw_funcs.get_inbox1_rptr = | |
189 | params->hw_funcs->get_inbox1_rptr; | |
190 | ||
191 | if (params->hw_funcs->set_inbox1_wptr) | |
192 | dmub->hw_funcs.set_inbox1_wptr = | |
193 | params->hw_funcs->set_inbox1_wptr; | |
194 | ||
195 | if (params->hw_funcs->is_supported) | |
196 | dmub->hw_funcs.is_supported = | |
197 | params->hw_funcs->is_supported; | |
198 | } | |
199 | ||
200 | /* Sanity checks for required hw func pointers. */ | |
201 | if (!dmub->hw_funcs.get_inbox1_rptr || | |
202 | !dmub->hw_funcs.set_inbox1_wptr) { | |
203 | status = DMUB_STATUS_INVALID; | |
204 | goto cleanup; | |
205 | } | |
206 | ||
207 | cleanup: | |
208 | if (status == DMUB_STATUS_OK) | |
209 | dmub->sw_init = true; | |
210 | else | |
211 | dmub_srv_destroy(dmub); | |
212 | ||
213 | return status; | |
214 | } | |
215 | ||
216 | void dmub_srv_destroy(struct dmub_srv *dmub) | |
217 | { | |
218 | dmub_memset(dmub, 0, sizeof(*dmub)); | |
219 | } | |
220 | ||
221 | enum dmub_status | |
222 | dmub_srv_calc_region_info(struct dmub_srv *dmub, | |
223 | const struct dmub_srv_region_params *params, | |
224 | struct dmub_srv_region_info *out) | |
225 | { | |
226 | struct dmub_region *inst = &out->regions[DMUB_WINDOW_0_INST_CONST]; | |
227 | struct dmub_region *stack = &out->regions[DMUB_WINDOW_1_STACK]; | |
228 | struct dmub_region *data = &out->regions[DMUB_WINDOW_2_BSS_DATA]; | |
229 | struct dmub_region *bios = &out->regions[DMUB_WINDOW_3_VBIOS]; | |
230 | struct dmub_region *mail = &out->regions[DMUB_WINDOW_4_MAILBOX]; | |
231 | struct dmub_region *trace_buff = &out->regions[DMUB_WINDOW_5_TRACEBUFF]; | |
2f39835c | 232 | struct dmub_region *fw_state = &out->regions[DMUB_WINDOW_6_FW_STATE]; |
2277f01d | 233 | struct dmub_region *scratch_mem = &out->regions[DMUB_WINDOW_7_SCRATCH_MEM]; |
1f0674fd NK |
234 | const struct dmub_fw_meta_info *fw_info; |
235 | uint32_t fw_state_size = DMUB_FW_STATE_SIZE; | |
236 | uint32_t trace_buffer_size = DMUB_TRACE_BUFFER_SIZE; | |
2277f01d | 237 | uint32_t scratch_mem_size = DMUB_SCRATCH_MEM_SIZE; |
7c008829 NK |
238 | |
239 | if (!dmub->sw_init) | |
240 | return DMUB_STATUS_INVALID; | |
241 | ||
242 | memset(out, 0, sizeof(*out)); | |
243 | ||
244 | out->num_regions = DMUB_NUM_WINDOWS; | |
245 | ||
246 | inst->base = 0x0; | |
247 | inst->top = inst->base + params->inst_const_size; | |
248 | ||
249 | data->base = dmub_align(inst->top, 256); | |
250 | data->top = data->base + params->bss_data_size; | |
251 | ||
1f0674fd NK |
252 | /* |
253 | * All cache windows below should be aligned to the size | |
254 | * of the DMCUB cache line, 64 bytes. | |
255 | */ | |
256 | ||
7c008829 NK |
257 | stack->base = dmub_align(data->top, 256); |
258 | stack->top = stack->base + DMUB_STACK_SIZE + DMUB_CONTEXT_SIZE; | |
259 | ||
260 | bios->base = dmub_align(stack->top, 256); | |
261 | bios->top = bios->base + params->vbios_size; | |
262 | ||
263 | mail->base = dmub_align(bios->top, 256); | |
264 | mail->top = mail->base + DMUB_MAILBOX_SIZE; | |
265 | ||
a576b345 | 266 | fw_info = dmub_get_fw_meta_info(params); |
1f0674fd NK |
267 | |
268 | if (fw_info) { | |
269 | fw_state_size = fw_info->fw_region_size; | |
270 | trace_buffer_size = fw_info->trace_buffer_size; | |
271 | } | |
272 | ||
7c008829 | 273 | trace_buff->base = dmub_align(mail->top, 256); |
1f0674fd | 274 | trace_buff->top = trace_buff->base + dmub_align(trace_buffer_size, 64); |
7c008829 | 275 | |
2f39835c | 276 | fw_state->base = dmub_align(trace_buff->top, 256); |
1f0674fd | 277 | fw_state->top = fw_state->base + dmub_align(fw_state_size, 64); |
2f39835c | 278 | |
2277f01d WW |
279 | scratch_mem->base = dmub_align(fw_state->top, 256); |
280 | scratch_mem->top = scratch_mem->base + dmub_align(scratch_mem_size, 64); | |
281 | ||
282 | out->fb_size = dmub_align(scratch_mem->top, 4096); | |
7c008829 NK |
283 | |
284 | return DMUB_STATUS_OK; | |
285 | } | |
286 | ||
287 | enum dmub_status dmub_srv_calc_fb_info(struct dmub_srv *dmub, | |
288 | const struct dmub_srv_fb_params *params, | |
289 | struct dmub_srv_fb_info *out) | |
290 | { | |
291 | uint8_t *cpu_base; | |
292 | uint64_t gpu_base; | |
293 | uint32_t i; | |
294 | ||
295 | if (!dmub->sw_init) | |
296 | return DMUB_STATUS_INVALID; | |
297 | ||
298 | memset(out, 0, sizeof(*out)); | |
299 | ||
300 | if (params->region_info->num_regions != DMUB_NUM_WINDOWS) | |
301 | return DMUB_STATUS_INVALID; | |
302 | ||
303 | cpu_base = (uint8_t *)params->cpu_addr; | |
304 | gpu_base = params->gpu_addr; | |
305 | ||
306 | for (i = 0; i < DMUB_NUM_WINDOWS; ++i) { | |
307 | const struct dmub_region *reg = | |
308 | ¶ms->region_info->regions[i]; | |
309 | ||
310 | out->fb[i].cpu_addr = cpu_base + reg->base; | |
311 | out->fb[i].gpu_addr = gpu_base + reg->base; | |
312 | out->fb[i].size = reg->top - reg->base; | |
313 | } | |
314 | ||
315 | out->num_fb = DMUB_NUM_WINDOWS; | |
316 | ||
317 | return DMUB_STATUS_OK; | |
318 | } | |
319 | ||
320 | enum dmub_status dmub_srv_has_hw_support(struct dmub_srv *dmub, | |
321 | bool *is_supported) | |
322 | { | |
323 | *is_supported = false; | |
324 | ||
325 | if (!dmub->sw_init) | |
326 | return DMUB_STATUS_INVALID; | |
327 | ||
328 | if (dmub->hw_funcs.is_supported) | |
329 | *is_supported = dmub->hw_funcs.is_supported(dmub); | |
330 | ||
331 | return DMUB_STATUS_OK; | |
332 | } | |
333 | ||
c09eeee4 NK |
334 | enum dmub_status dmub_srv_is_hw_init(struct dmub_srv *dmub, bool *is_hw_init) |
335 | { | |
336 | *is_hw_init = false; | |
337 | ||
338 | if (!dmub->sw_init) | |
339 | return DMUB_STATUS_INVALID; | |
340 | ||
e5f0b521 NK |
341 | if (!dmub->hw_init) |
342 | return DMUB_STATUS_OK; | |
343 | ||
c09eeee4 NK |
344 | if (dmub->hw_funcs.is_hw_init) |
345 | *is_hw_init = dmub->hw_funcs.is_hw_init(dmub); | |
346 | ||
347 | return DMUB_STATUS_OK; | |
348 | } | |
349 | ||
7c008829 NK |
350 | enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub, |
351 | const struct dmub_srv_hw_params *params) | |
352 | { | |
353 | struct dmub_fb *inst_fb = params->fb[DMUB_WINDOW_0_INST_CONST]; | |
354 | struct dmub_fb *stack_fb = params->fb[DMUB_WINDOW_1_STACK]; | |
355 | struct dmub_fb *data_fb = params->fb[DMUB_WINDOW_2_BSS_DATA]; | |
356 | struct dmub_fb *bios_fb = params->fb[DMUB_WINDOW_3_VBIOS]; | |
357 | struct dmub_fb *mail_fb = params->fb[DMUB_WINDOW_4_MAILBOX]; | |
358 | struct dmub_fb *tracebuff_fb = params->fb[DMUB_WINDOW_5_TRACEBUFF]; | |
2f39835c | 359 | struct dmub_fb *fw_state_fb = params->fb[DMUB_WINDOW_6_FW_STATE]; |
2277f01d | 360 | struct dmub_fb *scratch_mem_fb = params->fb[DMUB_WINDOW_7_SCRATCH_MEM]; |
7c008829 NK |
361 | |
362 | struct dmub_rb_init_params rb_params; | |
2f39835c | 363 | struct dmub_window cw0, cw1, cw2, cw3, cw4, cw5, cw6; |
7c008829 NK |
364 | struct dmub_region inbox1; |
365 | ||
366 | if (!dmub->sw_init) | |
367 | return DMUB_STATUS_INVALID; | |
368 | ||
369 | dmub->fb_base = params->fb_base; | |
370 | dmub->fb_offset = params->fb_offset; | |
371 | dmub->psp_version = params->psp_version; | |
372 | ||
373 | if (inst_fb && data_fb) { | |
374 | cw0.offset.quad_part = inst_fb->gpu_addr; | |
375 | cw0.region.base = DMUB_CW0_BASE; | |
376 | cw0.region.top = cw0.region.base + inst_fb->size - 1; | |
377 | ||
378 | cw1.offset.quad_part = stack_fb->gpu_addr; | |
379 | cw1.region.base = DMUB_CW1_BASE; | |
380 | cw1.region.top = cw1.region.base + stack_fb->size - 1; | |
381 | ||
dee5d542 NK |
382 | /** |
383 | * Read back all the instruction memory so we don't hang the | |
384 | * DMCUB when backdoor loading if the write from x86 hasn't been | |
385 | * flushed yet. This only occurs in backdoor loading. | |
386 | */ | |
387 | dmub_flush_buffer_mem(inst_fb); | |
388 | ||
ab16c736 | 389 | if (params->load_inst_const && dmub->hw_funcs.backdoor_load) |
7c008829 NK |
390 | dmub->hw_funcs.backdoor_load(dmub, &cw0, &cw1); |
391 | } | |
392 | ||
393 | if (dmub->hw_funcs.reset) | |
394 | dmub->hw_funcs.reset(dmub); | |
395 | ||
2f39835c | 396 | if (inst_fb && data_fb && bios_fb && mail_fb && tracebuff_fb && |
2277f01d | 397 | fw_state_fb && scratch_mem_fb) { |
7c008829 NK |
398 | cw2.offset.quad_part = data_fb->gpu_addr; |
399 | cw2.region.base = DMUB_CW0_BASE + inst_fb->size; | |
400 | cw2.region.top = cw2.region.base + data_fb->size; | |
401 | ||
402 | cw3.offset.quad_part = bios_fb->gpu_addr; | |
b9e9f11c | 403 | cw3.region.base = DMUB_CW3_BASE; |
7c008829 NK |
404 | cw3.region.top = cw3.region.base + bios_fb->size; |
405 | ||
406 | cw4.offset.quad_part = mail_fb->gpu_addr; | |
562c805f | 407 | cw4.region.base = DMUB_CW4_BASE; |
7c008829 NK |
408 | cw4.region.top = cw4.region.base + mail_fb->size; |
409 | ||
410 | inbox1.base = cw4.region.base; | |
411 | inbox1.top = cw4.region.top; | |
412 | ||
413 | cw5.offset.quad_part = tracebuff_fb->gpu_addr; | |
414 | cw5.region.base = DMUB_CW5_BASE; | |
415 | cw5.region.top = cw5.region.base + tracebuff_fb->size; | |
416 | ||
2f39835c NK |
417 | cw6.offset.quad_part = fw_state_fb->gpu_addr; |
418 | cw6.region.base = DMUB_CW6_BASE; | |
419 | cw6.region.top = cw6.region.base + fw_state_fb->size; | |
420 | ||
421 | dmub->fw_state = fw_state_fb->cpu_addr; | |
422 | ||
2277f01d WW |
423 | dmub->scratch_mem_fb = *scratch_mem_fb; |
424 | ||
7c008829 | 425 | if (dmub->hw_funcs.setup_windows) |
2f39835c NK |
426 | dmub->hw_funcs.setup_windows(dmub, &cw2, &cw3, &cw4, |
427 | &cw5, &cw6); | |
7c008829 NK |
428 | |
429 | if (dmub->hw_funcs.setup_mailbox) | |
430 | dmub->hw_funcs.setup_mailbox(dmub, &inbox1); | |
431 | } | |
432 | ||
433 | if (mail_fb) { | |
434 | dmub_memset(&rb_params, 0, sizeof(rb_params)); | |
435 | rb_params.ctx = dmub; | |
436 | rb_params.base_address = mail_fb->cpu_addr; | |
437 | rb_params.capacity = DMUB_RB_SIZE; | |
438 | ||
439 | dmub_rb_init(&dmub->inbox1_rb, &rb_params); | |
440 | } | |
441 | ||
442 | if (dmub->hw_funcs.reset_release) | |
443 | dmub->hw_funcs.reset_release(dmub); | |
444 | ||
445 | dmub->hw_init = true; | |
446 | ||
447 | return DMUB_STATUS_OK; | |
448 | } | |
449 | ||
0167da49 NK |
450 | enum dmub_status dmub_srv_hw_reset(struct dmub_srv *dmub) |
451 | { | |
452 | if (!dmub->sw_init) | |
453 | return DMUB_STATUS_INVALID; | |
454 | ||
455 | if (dmub->hw_init == false) | |
456 | return DMUB_STATUS_OK; | |
457 | ||
458 | if (dmub->hw_funcs.reset) | |
459 | dmub->hw_funcs.reset(dmub); | |
460 | ||
461 | dmub->hw_init = false; | |
462 | ||
463 | return DMUB_STATUS_OK; | |
464 | } | |
465 | ||
7c008829 | 466 | enum dmub_status dmub_srv_cmd_queue(struct dmub_srv *dmub, |
0ed3bcc4 | 467 | const union dmub_rb_cmd *cmd) |
7c008829 NK |
468 | { |
469 | if (!dmub->hw_init) | |
470 | return DMUB_STATUS_INVALID; | |
471 | ||
472 | if (dmub_rb_push_front(&dmub->inbox1_rb, cmd)) | |
473 | return DMUB_STATUS_OK; | |
474 | ||
475 | return DMUB_STATUS_QUEUE_FULL; | |
476 | } | |
477 | ||
478 | enum dmub_status dmub_srv_cmd_execute(struct dmub_srv *dmub) | |
479 | { | |
480 | if (!dmub->hw_init) | |
481 | return DMUB_STATUS_INVALID; | |
482 | ||
b7408a06 NK |
483 | /** |
484 | * Read back all the queued commands to ensure that they've | |
485 | * been flushed to framebuffer memory. Otherwise DMCUB might | |
486 | * read back stale, fully invalid or partially invalid data. | |
487 | */ | |
488 | dmub_rb_flush_pending(&dmub->inbox1_rb); | |
489 | ||
7c008829 NK |
490 | dmub->hw_funcs.set_inbox1_wptr(dmub, dmub->inbox1_rb.wrpt); |
491 | return DMUB_STATUS_OK; | |
492 | } | |
493 | ||
7c008829 NK |
494 | enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub, |
495 | uint32_t timeout_us) | |
496 | { | |
497 | uint32_t i; | |
498 | ||
a4942118 | 499 | if (!dmub->hw_init) |
7c008829 NK |
500 | return DMUB_STATUS_INVALID; |
501 | ||
a4942118 NK |
502 | if (!dmub->hw_funcs.is_auto_load_done) |
503 | return DMUB_STATUS_OK; | |
504 | ||
7c008829 NK |
505 | for (i = 0; i <= timeout_us; i += 100) { |
506 | if (dmub->hw_funcs.is_auto_load_done(dmub)) | |
507 | return DMUB_STATUS_OK; | |
508 | ||
509 | udelay(100); | |
510 | } | |
511 | ||
512 | return DMUB_STATUS_TIMEOUT; | |
513 | } | |
514 | ||
515 | enum dmub_status dmub_srv_wait_for_phy_init(struct dmub_srv *dmub, | |
516 | uint32_t timeout_us) | |
517 | { | |
b9e9f11c | 518 | uint32_t i = 0; |
7c008829 | 519 | |
a4942118 | 520 | if (!dmub->hw_init) |
7c008829 NK |
521 | return DMUB_STATUS_INVALID; |
522 | ||
a4942118 NK |
523 | if (!dmub->hw_funcs.is_phy_init) |
524 | return DMUB_STATUS_OK; | |
525 | ||
56fc13fe | 526 | for (i = 0; i <= timeout_us; i += 10) { |
7c008829 NK |
527 | if (dmub->hw_funcs.is_phy_init(dmub)) |
528 | return DMUB_STATUS_OK; | |
529 | ||
530 | udelay(10); | |
531 | } | |
532 | ||
56fc13fe | 533 | return DMUB_STATUS_TIMEOUT; |
7c008829 NK |
534 | } |
535 | ||
536 | enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub, | |
537 | uint32_t timeout_us) | |
538 | { | |
539 | uint32_t i; | |
540 | ||
541 | if (!dmub->hw_init) | |
542 | return DMUB_STATUS_INVALID; | |
543 | ||
544 | for (i = 0; i <= timeout_us; ++i) { | |
545 | dmub->inbox1_rb.rptr = dmub->hw_funcs.get_inbox1_rptr(dmub); | |
546 | if (dmub_rb_empty(&dmub->inbox1_rb)) | |
547 | return DMUB_STATUS_OK; | |
548 | ||
549 | udelay(1); | |
550 | } | |
551 | ||
552 | return DMUB_STATUS_TIMEOUT; | |
553 | } | |
fbbd3f8f NK |
554 | |
555 | enum dmub_status | |
556 | dmub_srv_send_gpint_command(struct dmub_srv *dmub, | |
557 | enum dmub_gpint_command command_code, | |
558 | uint16_t param, uint32_t timeout_us) | |
559 | { | |
560 | union dmub_gpint_data_register reg; | |
561 | uint32_t i; | |
562 | ||
563 | if (!dmub->sw_init) | |
564 | return DMUB_STATUS_INVALID; | |
565 | ||
566 | if (!dmub->hw_funcs.set_gpint) | |
567 | return DMUB_STATUS_INVALID; | |
568 | ||
569 | if (!dmub->hw_funcs.is_gpint_acked) | |
570 | return DMUB_STATUS_INVALID; | |
571 | ||
572 | reg.bits.status = 1; | |
573 | reg.bits.command_code = command_code; | |
574 | reg.bits.param = param; | |
575 | ||
576 | dmub->hw_funcs.set_gpint(dmub, reg); | |
577 | ||
578 | for (i = 0; i < timeout_us; ++i) { | |
579 | if (dmub->hw_funcs.is_gpint_acked(dmub, reg)) | |
580 | return DMUB_STATUS_OK; | |
581 | } | |
582 | ||
583 | return DMUB_STATUS_TIMEOUT; | |
584 | } | |
585 | ||
586 | enum dmub_status dmub_srv_get_gpint_response(struct dmub_srv *dmub, | |
587 | uint32_t *response) | |
588 | { | |
589 | *response = 0; | |
590 | ||
591 | if (!dmub->sw_init) | |
592 | return DMUB_STATUS_INVALID; | |
593 | ||
594 | if (!dmub->hw_funcs.get_gpint_response) | |
595 | return DMUB_STATUS_INVALID; | |
596 | ||
597 | *response = dmub->hw_funcs.get_gpint_response(dmub); | |
598 | ||
599 | return DMUB_STATUS_OK; | |
600 | } |