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