linux/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
<<
>>
Prefs
   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 "../dmub_srv.h"
  27#include "dmub_dcn20.h"
  28#include "dmub_dcn21.h"
  29#include "dmub_cmd.h"
  30#include "dmub_dcn30.h"
  31#include "dmub_dcn301.h"
  32#include "dmub_dcn302.h"
  33#include "dmub_dcn303.h"
  34#include "dmub_dcn31.h"
  35#include "os_types.h"
  36/*
  37 * Note: the DMUB service is standalone. No additional headers should be
  38 * added below or above this line unless they reside within the DMUB
  39 * folder.
  40 */
  41
  42/* Alignment for framebuffer memory. */
  43#define DMUB_FB_ALIGNMENT (1024 * 1024)
  44
  45/* Stack size. */
  46#define DMUB_STACK_SIZE (128 * 1024)
  47
  48/* Context size. */
  49#define DMUB_CONTEXT_SIZE (512 * 1024)
  50
  51/* Mailbox size : Ring buffers are required for both inbox and outbox */
  52#define DMUB_MAILBOX_SIZE ((2 * DMUB_RB_SIZE))
  53
  54/* Default state size if meta is absent. */
  55#define DMUB_FW_STATE_SIZE (64 * 1024)
  56
  57/* Default tracebuffer size if meta is absent. */
  58#define DMUB_TRACE_BUFFER_SIZE (64 * 1024)
  59
  60
  61/* Default scratch mem size. */
  62#define DMUB_SCRATCH_MEM_SIZE (256)
  63
  64/* Number of windows in use. */
  65#define DMUB_NUM_WINDOWS (DMUB_WINDOW_TOTAL)
  66/* Base addresses. */
  67
  68#define DMUB_CW0_BASE (0x60000000)
  69#define DMUB_CW1_BASE (0x61000000)
  70#define DMUB_CW3_BASE (0x63000000)
  71#define DMUB_CW4_BASE (0x64000000)
  72#define DMUB_CW5_BASE (0x65000000)
  73#define DMUB_CW6_BASE (0x66000000)
  74
  75#define DMUB_REGION5_BASE (0xA0000000)
  76
  77static inline uint32_t dmub_align(uint32_t val, uint32_t factor)
  78{
  79        return (val + factor - 1) / factor * factor;
  80}
  81
  82void dmub_flush_buffer_mem(const struct dmub_fb *fb)
  83{
  84        const uint8_t *base = (const uint8_t *)fb->cpu_addr;
  85        uint8_t buf[64];
  86        uint32_t pos, end;
  87
  88        /**
  89         * Read 64-byte chunks since we don't want to store a
  90         * large temporary buffer for this purpose.
  91         */
  92        end = fb->size / sizeof(buf) * sizeof(buf);
  93
  94        for (pos = 0; pos < end; pos += sizeof(buf))
  95                dmub_memcpy(buf, base + pos, sizeof(buf));
  96
  97        /* Read anything leftover into the buffer. */
  98        if (end < fb->size)
  99                dmub_memcpy(buf, base + pos, fb->size - end);
 100}
 101
 102static const struct dmub_fw_meta_info *
 103dmub_get_fw_meta_info(const struct dmub_srv_region_params *params)
 104{
 105        const union dmub_fw_meta *meta;
 106        const uint8_t *blob = NULL;
 107        uint32_t blob_size = 0;
 108        uint32_t meta_offset = 0;
 109
 110        if (params->fw_bss_data && params->bss_data_size) {
 111                /* Legacy metadata region. */
 112                blob = params->fw_bss_data;
 113                blob_size = params->bss_data_size;
 114                meta_offset = DMUB_FW_META_OFFSET;
 115        } else if (params->fw_inst_const && params->inst_const_size) {
 116                /* Combined metadata region. */
 117                blob = params->fw_inst_const;
 118                blob_size = params->inst_const_size;
 119                meta_offset = 0;
 120        }
 121
 122        if (!blob || !blob_size)
 123                return NULL;
 124
 125        if (blob_size < sizeof(union dmub_fw_meta) + meta_offset)
 126                return NULL;
 127
 128        meta = (const union dmub_fw_meta *)(blob + blob_size - meta_offset -
 129                                            sizeof(union dmub_fw_meta));
 130
 131        if (meta->info.magic_value != DMUB_FW_META_MAGIC)
 132                return NULL;
 133
 134        return &meta->info;
 135}
 136
 137static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
 138{
 139        struct dmub_srv_hw_funcs *funcs = &dmub->hw_funcs;
 140
 141        switch (asic) {
 142        case DMUB_ASIC_DCN20:
 143        case DMUB_ASIC_DCN21:
 144        case DMUB_ASIC_DCN30:
 145        case DMUB_ASIC_DCN301:
 146        case DMUB_ASIC_DCN302:
 147        case DMUB_ASIC_DCN303:
 148                dmub->regs = &dmub_srv_dcn20_regs;
 149
 150                funcs->reset = dmub_dcn20_reset;
 151                funcs->reset_release = dmub_dcn20_reset_release;
 152                funcs->backdoor_load = dmub_dcn20_backdoor_load;
 153                funcs->setup_windows = dmub_dcn20_setup_windows;
 154                funcs->setup_mailbox = dmub_dcn20_setup_mailbox;
 155                funcs->get_inbox1_rptr = dmub_dcn20_get_inbox1_rptr;
 156                funcs->set_inbox1_wptr = dmub_dcn20_set_inbox1_wptr;
 157                funcs->is_supported = dmub_dcn20_is_supported;
 158                funcs->is_hw_init = dmub_dcn20_is_hw_init;
 159                funcs->set_gpint = dmub_dcn20_set_gpint;
 160                funcs->is_gpint_acked = dmub_dcn20_is_gpint_acked;
 161                funcs->get_gpint_response = dmub_dcn20_get_gpint_response;
 162                funcs->get_fw_status = dmub_dcn20_get_fw_boot_status;
 163                funcs->enable_dmub_boot_options = dmub_dcn20_enable_dmub_boot_options;
 164                funcs->skip_dmub_panel_power_sequence = dmub_dcn20_skip_dmub_panel_power_sequence;
 165                funcs->get_current_time = dmub_dcn20_get_current_time;
 166
 167                // Out mailbox register access functions for RN and above
 168                funcs->setup_out_mailbox = dmub_dcn20_setup_out_mailbox;
 169                funcs->get_outbox1_wptr = dmub_dcn20_get_outbox1_wptr;
 170                funcs->set_outbox1_rptr = dmub_dcn20_set_outbox1_rptr;
 171
 172                //outbox0 call stacks
 173                funcs->setup_outbox0 = dmub_dcn20_setup_outbox0;
 174                funcs->get_outbox0_wptr = dmub_dcn20_get_outbox0_wptr;
 175                funcs->set_outbox0_rptr = dmub_dcn20_set_outbox0_rptr;
 176
 177                funcs->get_diagnostic_data = dmub_dcn20_get_diagnostic_data;
 178
 179                if (asic == DMUB_ASIC_DCN21) {
 180                        dmub->regs = &dmub_srv_dcn21_regs;
 181
 182                        funcs->is_phy_init = dmub_dcn21_is_phy_init;
 183                }
 184                if (asic == DMUB_ASIC_DCN30) {
 185                        dmub->regs = &dmub_srv_dcn30_regs;
 186
 187                        funcs->backdoor_load = dmub_dcn30_backdoor_load;
 188                        funcs->setup_windows = dmub_dcn30_setup_windows;
 189                }
 190                if (asic == DMUB_ASIC_DCN301) {
 191                        dmub->regs = &dmub_srv_dcn301_regs;
 192
 193                        funcs->backdoor_load = dmub_dcn30_backdoor_load;
 194                        funcs->setup_windows = dmub_dcn30_setup_windows;
 195                }
 196                if (asic == DMUB_ASIC_DCN302) {
 197                        dmub->regs = &dmub_srv_dcn302_regs;
 198
 199                        funcs->backdoor_load = dmub_dcn30_backdoor_load;
 200                        funcs->setup_windows = dmub_dcn30_setup_windows;
 201                }
 202                if (asic == DMUB_ASIC_DCN303) {
 203                        dmub->regs = &dmub_srv_dcn303_regs;
 204
 205                        funcs->backdoor_load = dmub_dcn30_backdoor_load;
 206                        funcs->setup_windows = dmub_dcn30_setup_windows;
 207                }
 208                break;
 209
 210        case DMUB_ASIC_DCN31:
 211                dmub->regs_dcn31 = &dmub_srv_dcn31_regs;
 212                funcs->reset = dmub_dcn31_reset;
 213                funcs->reset_release = dmub_dcn31_reset_release;
 214                funcs->backdoor_load = dmub_dcn31_backdoor_load;
 215                funcs->setup_windows = dmub_dcn31_setup_windows;
 216                funcs->setup_mailbox = dmub_dcn31_setup_mailbox;
 217                funcs->get_inbox1_rptr = dmub_dcn31_get_inbox1_rptr;
 218                funcs->set_inbox1_wptr = dmub_dcn31_set_inbox1_wptr;
 219                funcs->setup_out_mailbox = dmub_dcn31_setup_out_mailbox;
 220                funcs->get_outbox1_wptr = dmub_dcn31_get_outbox1_wptr;
 221                funcs->set_outbox1_rptr = dmub_dcn31_set_outbox1_rptr;
 222                funcs->is_supported = dmub_dcn31_is_supported;
 223                funcs->is_hw_init = dmub_dcn31_is_hw_init;
 224                funcs->set_gpint = dmub_dcn31_set_gpint;
 225                funcs->is_gpint_acked = dmub_dcn31_is_gpint_acked;
 226                funcs->get_gpint_response = dmub_dcn31_get_gpint_response;
 227                funcs->get_gpint_dataout = dmub_dcn31_get_gpint_dataout;
 228                funcs->get_fw_status = dmub_dcn31_get_fw_boot_status;
 229                funcs->enable_dmub_boot_options = dmub_dcn31_enable_dmub_boot_options;
 230                funcs->skip_dmub_panel_power_sequence = dmub_dcn31_skip_dmub_panel_power_sequence;
 231                //outbox0 call stacks
 232                funcs->setup_outbox0 = dmub_dcn31_setup_outbox0;
 233                funcs->get_outbox0_wptr = dmub_dcn31_get_outbox0_wptr;
 234                funcs->set_outbox0_rptr = dmub_dcn31_set_outbox0_rptr;
 235
 236                funcs->get_diagnostic_data = dmub_dcn31_get_diagnostic_data;
 237
 238                funcs->get_current_time = dmub_dcn31_get_current_time;
 239
 240                break;
 241
 242        default:
 243                return false;
 244        }
 245
 246        return true;
 247}
 248
 249enum dmub_status dmub_srv_create(struct dmub_srv *dmub,
 250                                 const struct dmub_srv_create_params *params)
 251{
 252        enum dmub_status status = DMUB_STATUS_OK;
 253
 254        dmub_memset(dmub, 0, sizeof(*dmub));
 255
 256        dmub->funcs = params->funcs;
 257        dmub->user_ctx = params->user_ctx;
 258        dmub->asic = params->asic;
 259        dmub->fw_version = params->fw_version;
 260        dmub->is_virtual = params->is_virtual;
 261
 262        /* Setup asic dependent hardware funcs. */
 263        if (!dmub_srv_hw_setup(dmub, params->asic)) {
 264                status = DMUB_STATUS_INVALID;
 265                goto cleanup;
 266        }
 267
 268        /* Override (some) hardware funcs based on user params. */
 269        if (params->hw_funcs) {
 270                if (params->hw_funcs->emul_get_inbox1_rptr)
 271                        dmub->hw_funcs.emul_get_inbox1_rptr =
 272                                params->hw_funcs->emul_get_inbox1_rptr;
 273
 274                if (params->hw_funcs->emul_set_inbox1_wptr)
 275                        dmub->hw_funcs.emul_set_inbox1_wptr =
 276                                params->hw_funcs->emul_set_inbox1_wptr;
 277
 278                if (params->hw_funcs->is_supported)
 279                        dmub->hw_funcs.is_supported =
 280                                params->hw_funcs->is_supported;
 281        }
 282
 283        /* Sanity checks for required hw func pointers. */
 284        if (!dmub->hw_funcs.get_inbox1_rptr ||
 285            !dmub->hw_funcs.set_inbox1_wptr) {
 286                status = DMUB_STATUS_INVALID;
 287                goto cleanup;
 288        }
 289
 290cleanup:
 291        if (status == DMUB_STATUS_OK)
 292                dmub->sw_init = true;
 293        else
 294                dmub_srv_destroy(dmub);
 295
 296        return status;
 297}
 298
 299void dmub_srv_destroy(struct dmub_srv *dmub)
 300{
 301        dmub_memset(dmub, 0, sizeof(*dmub));
 302}
 303
 304enum dmub_status
 305dmub_srv_calc_region_info(struct dmub_srv *dmub,
 306                          const struct dmub_srv_region_params *params,
 307                          struct dmub_srv_region_info *out)
 308{
 309        struct dmub_region *inst = &out->regions[DMUB_WINDOW_0_INST_CONST];
 310        struct dmub_region *stack = &out->regions[DMUB_WINDOW_1_STACK];
 311        struct dmub_region *data = &out->regions[DMUB_WINDOW_2_BSS_DATA];
 312        struct dmub_region *bios = &out->regions[DMUB_WINDOW_3_VBIOS];
 313        struct dmub_region *mail = &out->regions[DMUB_WINDOW_4_MAILBOX];
 314        struct dmub_region *trace_buff = &out->regions[DMUB_WINDOW_5_TRACEBUFF];
 315        struct dmub_region *fw_state = &out->regions[DMUB_WINDOW_6_FW_STATE];
 316        struct dmub_region *scratch_mem = &out->regions[DMUB_WINDOW_7_SCRATCH_MEM];
 317        const struct dmub_fw_meta_info *fw_info;
 318        uint32_t fw_state_size = DMUB_FW_STATE_SIZE;
 319        uint32_t trace_buffer_size = DMUB_TRACE_BUFFER_SIZE;
 320        uint32_t scratch_mem_size = DMUB_SCRATCH_MEM_SIZE;
 321
 322        if (!dmub->sw_init)
 323                return DMUB_STATUS_INVALID;
 324
 325        memset(out, 0, sizeof(*out));
 326
 327        out->num_regions = DMUB_NUM_WINDOWS;
 328
 329        inst->base = 0x0;
 330        inst->top = inst->base + params->inst_const_size;
 331
 332        data->base = dmub_align(inst->top, 256);
 333        data->top = data->base + params->bss_data_size;
 334
 335        /*
 336         * All cache windows below should be aligned to the size
 337         * of the DMCUB cache line, 64 bytes.
 338         */
 339
 340        stack->base = dmub_align(data->top, 256);
 341        stack->top = stack->base + DMUB_STACK_SIZE + DMUB_CONTEXT_SIZE;
 342
 343        bios->base = dmub_align(stack->top, 256);
 344        bios->top = bios->base + params->vbios_size;
 345
 346        mail->base = dmub_align(bios->top, 256);
 347        mail->top = mail->base + DMUB_MAILBOX_SIZE;
 348
 349        fw_info = dmub_get_fw_meta_info(params);
 350
 351        if (fw_info) {
 352                fw_state_size = fw_info->fw_region_size;
 353                trace_buffer_size = fw_info->trace_buffer_size;
 354
 355                /**
 356                 * If DM didn't fill in a version, then fill it in based on
 357                 * the firmware meta now that we have it.
 358                 *
 359                 * TODO: Make it easier for driver to extract this out to
 360                 * pass during creation.
 361                 */
 362                if (dmub->fw_version == 0)
 363                        dmub->fw_version = fw_info->fw_version;
 364        }
 365
 366        trace_buff->base = dmub_align(mail->top, 256);
 367        trace_buff->top = trace_buff->base + dmub_align(trace_buffer_size, 64);
 368
 369        fw_state->base = dmub_align(trace_buff->top, 256);
 370        fw_state->top = fw_state->base + dmub_align(fw_state_size, 64);
 371
 372        scratch_mem->base = dmub_align(fw_state->top, 256);
 373        scratch_mem->top = scratch_mem->base + dmub_align(scratch_mem_size, 64);
 374
 375        out->fb_size = dmub_align(scratch_mem->top, 4096);
 376
 377        return DMUB_STATUS_OK;
 378}
 379
 380enum dmub_status dmub_srv_calc_fb_info(struct dmub_srv *dmub,
 381                                       const struct dmub_srv_fb_params *params,
 382                                       struct dmub_srv_fb_info *out)
 383{
 384        uint8_t *cpu_base;
 385        uint64_t gpu_base;
 386        uint32_t i;
 387
 388        if (!dmub->sw_init)
 389                return DMUB_STATUS_INVALID;
 390
 391        memset(out, 0, sizeof(*out));
 392
 393        if (params->region_info->num_regions != DMUB_NUM_WINDOWS)
 394                return DMUB_STATUS_INVALID;
 395
 396        cpu_base = (uint8_t *)params->cpu_addr;
 397        gpu_base = params->gpu_addr;
 398
 399        for (i = 0; i < DMUB_NUM_WINDOWS; ++i) {
 400                const struct dmub_region *reg =
 401                        &params->region_info->regions[i];
 402
 403                out->fb[i].cpu_addr = cpu_base + reg->base;
 404                out->fb[i].gpu_addr = gpu_base + reg->base;
 405                out->fb[i].size = reg->top - reg->base;
 406        }
 407
 408        out->num_fb = DMUB_NUM_WINDOWS;
 409
 410        return DMUB_STATUS_OK;
 411}
 412
 413enum dmub_status dmub_srv_has_hw_support(struct dmub_srv *dmub,
 414                                         bool *is_supported)
 415{
 416        *is_supported = false;
 417
 418        if (!dmub->sw_init)
 419                return DMUB_STATUS_INVALID;
 420
 421        if (dmub->hw_funcs.is_supported)
 422                *is_supported = dmub->hw_funcs.is_supported(dmub);
 423
 424        return DMUB_STATUS_OK;
 425}
 426
 427enum dmub_status dmub_srv_is_hw_init(struct dmub_srv *dmub, bool *is_hw_init)
 428{
 429        *is_hw_init = false;
 430
 431        if (!dmub->sw_init)
 432                return DMUB_STATUS_INVALID;
 433
 434        if (!dmub->hw_init)
 435                return DMUB_STATUS_OK;
 436
 437        if (dmub->hw_funcs.is_hw_init)
 438                *is_hw_init = dmub->hw_funcs.is_hw_init(dmub);
 439
 440        return DMUB_STATUS_OK;
 441}
 442
 443enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub,
 444                                  const struct dmub_srv_hw_params *params)
 445{
 446        struct dmub_fb *inst_fb = params->fb[DMUB_WINDOW_0_INST_CONST];
 447        struct dmub_fb *stack_fb = params->fb[DMUB_WINDOW_1_STACK];
 448        struct dmub_fb *data_fb = params->fb[DMUB_WINDOW_2_BSS_DATA];
 449        struct dmub_fb *bios_fb = params->fb[DMUB_WINDOW_3_VBIOS];
 450        struct dmub_fb *mail_fb = params->fb[DMUB_WINDOW_4_MAILBOX];
 451        struct dmub_fb *tracebuff_fb = params->fb[DMUB_WINDOW_5_TRACEBUFF];
 452        struct dmub_fb *fw_state_fb = params->fb[DMUB_WINDOW_6_FW_STATE];
 453        struct dmub_fb *scratch_mem_fb = params->fb[DMUB_WINDOW_7_SCRATCH_MEM];
 454
 455        struct dmub_rb_init_params rb_params, outbox0_rb_params;
 456        struct dmub_window cw0, cw1, cw2, cw3, cw4, cw5, cw6;
 457        struct dmub_region inbox1, outbox1, outbox0;
 458
 459        if (!dmub->sw_init)
 460                return DMUB_STATUS_INVALID;
 461
 462        if (!inst_fb || !stack_fb || !data_fb || !bios_fb || !mail_fb ||
 463                !tracebuff_fb || !fw_state_fb || !scratch_mem_fb) {
 464                ASSERT(0);
 465                return DMUB_STATUS_INVALID;
 466        }
 467
 468        dmub->fb_base = params->fb_base;
 469        dmub->fb_offset = params->fb_offset;
 470        dmub->psp_version = params->psp_version;
 471
 472        if (dmub->hw_funcs.reset)
 473                dmub->hw_funcs.reset(dmub);
 474
 475        cw0.offset.quad_part = inst_fb->gpu_addr;
 476        cw0.region.base = DMUB_CW0_BASE;
 477        cw0.region.top = cw0.region.base + inst_fb->size - 1;
 478
 479        cw1.offset.quad_part = stack_fb->gpu_addr;
 480        cw1.region.base = DMUB_CW1_BASE;
 481        cw1.region.top = cw1.region.base + stack_fb->size - 1;
 482
 483        if (params->load_inst_const && dmub->hw_funcs.backdoor_load) {
 484                /**
 485                 * Read back all the instruction memory so we don't hang the
 486                 * DMCUB when backdoor loading if the write from x86 hasn't been
 487                 * flushed yet. This only occurs in backdoor loading.
 488                 */
 489                dmub_flush_buffer_mem(inst_fb);
 490                dmub->hw_funcs.backdoor_load(dmub, &cw0, &cw1);
 491        }
 492
 493        cw2.offset.quad_part = data_fb->gpu_addr;
 494        cw2.region.base = DMUB_CW0_BASE + inst_fb->size;
 495        cw2.region.top = cw2.region.base + data_fb->size;
 496
 497        cw3.offset.quad_part = bios_fb->gpu_addr;
 498        cw3.region.base = DMUB_CW3_BASE;
 499        cw3.region.top = cw3.region.base + bios_fb->size;
 500
 501        cw4.offset.quad_part = mail_fb->gpu_addr;
 502        cw4.region.base = DMUB_CW4_BASE;
 503        cw4.region.top = cw4.region.base + mail_fb->size;
 504
 505        /**
 506         * Doubled the mailbox region to accomodate inbox and outbox.
 507         * Note: Currently, currently total mailbox size is 16KB. It is split
 508         * equally into 8KB between inbox and outbox. If this config is
 509         * changed, then uncached base address configuration of outbox1
 510         * has to be updated in funcs->setup_out_mailbox.
 511         */
 512        inbox1.base = cw4.region.base;
 513        inbox1.top = cw4.region.base + DMUB_RB_SIZE;
 514        outbox1.base = inbox1.top;
 515        outbox1.top = cw4.region.top;
 516
 517        cw5.offset.quad_part = tracebuff_fb->gpu_addr;
 518        cw5.region.base = DMUB_CW5_BASE;
 519        cw5.region.top = cw5.region.base + tracebuff_fb->size;
 520
 521        outbox0.base = DMUB_REGION5_BASE + TRACE_BUFFER_ENTRY_OFFSET;
 522        outbox0.top = outbox0.base + tracebuff_fb->size - TRACE_BUFFER_ENTRY_OFFSET;
 523
 524        cw6.offset.quad_part = fw_state_fb->gpu_addr;
 525        cw6.region.base = DMUB_CW6_BASE;
 526        cw6.region.top = cw6.region.base + fw_state_fb->size;
 527
 528        dmub->fw_state = fw_state_fb->cpu_addr;
 529
 530        dmub->scratch_mem_fb = *scratch_mem_fb;
 531
 532        if (dmub->hw_funcs.setup_windows)
 533                dmub->hw_funcs.setup_windows(dmub, &cw2, &cw3, &cw4, &cw5, &cw6);
 534
 535        if (dmub->hw_funcs.setup_outbox0)
 536                dmub->hw_funcs.setup_outbox0(dmub, &outbox0);
 537
 538        if (dmub->hw_funcs.setup_mailbox)
 539                dmub->hw_funcs.setup_mailbox(dmub, &inbox1);
 540        if (dmub->hw_funcs.setup_out_mailbox)
 541                dmub->hw_funcs.setup_out_mailbox(dmub, &outbox1);
 542
 543        dmub_memset(&rb_params, 0, sizeof(rb_params));
 544        rb_params.ctx = dmub;
 545        rb_params.base_address = mail_fb->cpu_addr;
 546        rb_params.capacity = DMUB_RB_SIZE;
 547        dmub_rb_init(&dmub->inbox1_rb, &rb_params);
 548
 549        // Initialize outbox1 ring buffer
 550        rb_params.ctx = dmub;
 551        rb_params.base_address = (void *) ((uint8_t *) (mail_fb->cpu_addr) + DMUB_RB_SIZE);
 552        rb_params.capacity = DMUB_RB_SIZE;
 553        dmub_rb_init(&dmub->outbox1_rb, &rb_params);
 554
 555        dmub_memset(&outbox0_rb_params, 0, sizeof(outbox0_rb_params));
 556        outbox0_rb_params.ctx = dmub;
 557        outbox0_rb_params.base_address = (void *)((uintptr_t)(tracebuff_fb->cpu_addr) + TRACE_BUFFER_ENTRY_OFFSET);
 558        outbox0_rb_params.capacity = tracebuff_fb->size - dmub_align(TRACE_BUFFER_ENTRY_OFFSET, 64);
 559        dmub_rb_init(&dmub->outbox0_rb, &outbox0_rb_params);
 560
 561        /* Report to DMUB what features are supported by current driver */
 562        if (dmub->hw_funcs.enable_dmub_boot_options)
 563                dmub->hw_funcs.enable_dmub_boot_options(dmub, params);
 564
 565        if (dmub->hw_funcs.reset_release)
 566                dmub->hw_funcs.reset_release(dmub);
 567
 568        dmub->hw_init = true;
 569
 570        return DMUB_STATUS_OK;
 571}
 572
 573enum dmub_status dmub_srv_hw_reset(struct dmub_srv *dmub)
 574{
 575        if (!dmub->sw_init)
 576                return DMUB_STATUS_INVALID;
 577
 578        if (dmub->hw_funcs.reset)
 579                dmub->hw_funcs.reset(dmub);
 580
 581        dmub->hw_init = false;
 582
 583        return DMUB_STATUS_OK;
 584}
 585
 586enum dmub_status dmub_srv_cmd_queue(struct dmub_srv *dmub,
 587                                    const union dmub_rb_cmd *cmd)
 588{
 589        if (!dmub->hw_init)
 590                return DMUB_STATUS_INVALID;
 591
 592        if (dmub_rb_push_front(&dmub->inbox1_rb, cmd))
 593                return DMUB_STATUS_OK;
 594
 595        return DMUB_STATUS_QUEUE_FULL;
 596}
 597
 598enum dmub_status dmub_srv_cmd_execute(struct dmub_srv *dmub)
 599{
 600        if (!dmub->hw_init)
 601                return DMUB_STATUS_INVALID;
 602
 603        /**
 604         * Read back all the queued commands to ensure that they've
 605         * been flushed to framebuffer memory. Otherwise DMCUB might
 606         * read back stale, fully invalid or partially invalid data.
 607         */
 608        dmub_rb_flush_pending(&dmub->inbox1_rb);
 609
 610                dmub->hw_funcs.set_inbox1_wptr(dmub, dmub->inbox1_rb.wrpt);
 611        return DMUB_STATUS_OK;
 612}
 613
 614enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub,
 615                                             uint32_t timeout_us)
 616{
 617        uint32_t i;
 618
 619        if (!dmub->hw_init)
 620                return DMUB_STATUS_INVALID;
 621
 622        for (i = 0; i <= timeout_us; i += 100) {
 623                union dmub_fw_boot_status status = dmub->hw_funcs.get_fw_status(dmub);
 624
 625                if (status.bits.dal_fw && status.bits.mailbox_rdy)
 626                        return DMUB_STATUS_OK;
 627
 628                udelay(100);
 629        }
 630
 631        return DMUB_STATUS_TIMEOUT;
 632}
 633
 634enum dmub_status dmub_srv_wait_for_phy_init(struct dmub_srv *dmub,
 635                                            uint32_t timeout_us)
 636{
 637        uint32_t i = 0;
 638
 639        if (!dmub->hw_init)
 640                return DMUB_STATUS_INVALID;
 641
 642        if (!dmub->hw_funcs.is_phy_init)
 643                return DMUB_STATUS_OK;
 644
 645        for (i = 0; i <= timeout_us; i += 10) {
 646                if (dmub->hw_funcs.is_phy_init(dmub))
 647                        return DMUB_STATUS_OK;
 648
 649                udelay(10);
 650        }
 651
 652        return DMUB_STATUS_TIMEOUT;
 653}
 654
 655enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub,
 656                                        uint32_t timeout_us)
 657{
 658        uint32_t i;
 659
 660        if (!dmub->hw_init)
 661                return DMUB_STATUS_INVALID;
 662
 663        for (i = 0; i <= timeout_us; ++i) {
 664                        dmub->inbox1_rb.rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
 665                if (dmub_rb_empty(&dmub->inbox1_rb))
 666                        return DMUB_STATUS_OK;
 667
 668                udelay(1);
 669        }
 670
 671        return DMUB_STATUS_TIMEOUT;
 672}
 673
 674enum dmub_status
 675dmub_srv_send_gpint_command(struct dmub_srv *dmub,
 676                            enum dmub_gpint_command command_code,
 677                            uint16_t param, uint32_t timeout_us)
 678{
 679        union dmub_gpint_data_register reg;
 680        uint32_t i;
 681
 682        if (!dmub->sw_init)
 683                return DMUB_STATUS_INVALID;
 684
 685        if (!dmub->hw_funcs.set_gpint)
 686                return DMUB_STATUS_INVALID;
 687
 688        if (!dmub->hw_funcs.is_gpint_acked)
 689                return DMUB_STATUS_INVALID;
 690
 691        reg.bits.status = 1;
 692        reg.bits.command_code = command_code;
 693        reg.bits.param = param;
 694
 695        dmub->hw_funcs.set_gpint(dmub, reg);
 696
 697        for (i = 0; i < timeout_us; ++i) {
 698                udelay(1);
 699
 700                if (dmub->hw_funcs.is_gpint_acked(dmub, reg))
 701                        return DMUB_STATUS_OK;
 702        }
 703
 704        return DMUB_STATUS_TIMEOUT;
 705}
 706
 707enum dmub_status dmub_srv_get_gpint_response(struct dmub_srv *dmub,
 708                                             uint32_t *response)
 709{
 710        *response = 0;
 711
 712        if (!dmub->sw_init)
 713                return DMUB_STATUS_INVALID;
 714
 715        if (!dmub->hw_funcs.get_gpint_response)
 716                return DMUB_STATUS_INVALID;
 717
 718        *response = dmub->hw_funcs.get_gpint_response(dmub);
 719
 720        return DMUB_STATUS_OK;
 721}
 722
 723enum dmub_status dmub_srv_get_gpint_dataout(struct dmub_srv *dmub,
 724                                             uint32_t *dataout)
 725{
 726        *dataout = 0;
 727
 728        if (!dmub->sw_init)
 729                return DMUB_STATUS_INVALID;
 730
 731        if (!dmub->hw_funcs.get_gpint_dataout)
 732                return DMUB_STATUS_INVALID;
 733
 734        *dataout = dmub->hw_funcs.get_gpint_dataout(dmub);
 735
 736        return DMUB_STATUS_OK;
 737}
 738
 739enum dmub_status dmub_srv_get_fw_boot_status(struct dmub_srv *dmub,
 740                                             union dmub_fw_boot_status *status)
 741{
 742        status->all = 0;
 743
 744        if (!dmub->sw_init)
 745                return DMUB_STATUS_INVALID;
 746
 747        if (dmub->hw_funcs.get_fw_status)
 748                *status = dmub->hw_funcs.get_fw_status(dmub);
 749
 750        return DMUB_STATUS_OK;
 751}
 752
 753enum dmub_status dmub_srv_cmd_with_reply_data(struct dmub_srv *dmub,
 754                                              union dmub_rb_cmd *cmd)
 755{
 756        enum dmub_status status = DMUB_STATUS_OK;
 757
 758        // Queue command
 759        status = dmub_srv_cmd_queue(dmub, cmd);
 760
 761        if (status != DMUB_STATUS_OK)
 762                return status;
 763
 764        // Execute command
 765        status = dmub_srv_cmd_execute(dmub);
 766
 767        if (status != DMUB_STATUS_OK)
 768                return status;
 769
 770        // Wait for DMUB to process command
 771        status = dmub_srv_wait_for_idle(dmub, 100000);
 772
 773        if (status != DMUB_STATUS_OK)
 774                return status;
 775
 776        // Copy data back from ring buffer into command
 777        dmub_rb_get_return_data(&dmub->inbox1_rb, cmd);
 778
 779        return status;
 780}
 781
 782static inline bool dmub_rb_out_trace_buffer_front(struct dmub_rb *rb,
 783                                 void *entry)
 784{
 785        const uint64_t *src = (const uint64_t *)(rb->base_address) + rb->rptr / sizeof(uint64_t);
 786        uint64_t *dst = (uint64_t *)entry;
 787        uint8_t i;
 788        uint8_t loop_count;
 789
 790        if (rb->rptr == rb->wrpt)
 791                return false;
 792
 793        loop_count = sizeof(struct dmcub_trace_buf_entry) / sizeof(uint64_t);
 794        // copying data
 795        for (i = 0; i < loop_count; i++)
 796                *dst++ = *src++;
 797
 798        rb->rptr += sizeof(struct dmcub_trace_buf_entry);
 799
 800        rb->rptr %= rb->capacity;
 801
 802        return true;
 803}
 804
 805bool dmub_srv_get_outbox0_msg(struct dmub_srv *dmub, struct dmcub_trace_buf_entry *entry)
 806{
 807        dmub->outbox0_rb.wrpt = dmub->hw_funcs.get_outbox0_wptr(dmub);
 808
 809        return dmub_rb_out_trace_buffer_front(&dmub->outbox0_rb, (void *)entry);
 810}
 811
 812bool dmub_srv_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data)
 813{
 814        if (!dmub || !dmub->hw_funcs.get_diagnostic_data || !diag_data)
 815                return false;
 816        dmub->hw_funcs.get_diagnostic_data(dmub, diag_data);
 817        return true;
 818}
 819