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 ¶ms->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 410 return DMUB_STATUS_TIMEOUT; 411 } 412 413 enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub, 414 uint32_t timeout_us) 415 { 416 uint32_t i; 417 418 if (!dmub->hw_init) 419 return DMUB_STATUS_INVALID; 420 421 for (i = 0; i <= timeout_us; ++i) { 422 dmub->inbox1_rb.rptr = dmub->hw_funcs.get_inbox1_rptr(dmub); 423 if (dmub_rb_empty(&dmub->inbox1_rb)) 424 return DMUB_STATUS_OK; 425 426 udelay(1); 427 } 428 429 return DMUB_STATUS_TIMEOUT; 430 } 431