linux/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.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_psr.h"
  27#include "dc.h"
  28#include "dc_dmub_srv.h"
  29#include "dmub/dmub_srv.h"
  30#include "core_types.h"
  31
  32#define MAX_PIPES 6
  33
  34/*
  35 * Convert dmcub psr state to dmcu psr state.
  36 */
  37static enum dc_psr_state convert_psr_state(uint32_t raw_state)
  38{
  39        enum dc_psr_state state = PSR_STATE0;
  40
  41        if (raw_state == 0)
  42                state = PSR_STATE0;
  43        else if (raw_state == 0x10)
  44                state = PSR_STATE1;
  45        else if (raw_state == 0x11)
  46                state = PSR_STATE1a;
  47        else if (raw_state == 0x20)
  48                state = PSR_STATE2;
  49        else if (raw_state == 0x21)
  50                state = PSR_STATE2a;
  51        else if (raw_state == 0x30)
  52                state = PSR_STATE3;
  53        else if (raw_state == 0x31)
  54                state = PSR_STATE3Init;
  55        else if (raw_state == 0x40)
  56                state = PSR_STATE4;
  57        else if (raw_state == 0x41)
  58                state = PSR_STATE4a;
  59        else if (raw_state == 0x42)
  60                state = PSR_STATE4b;
  61        else if (raw_state == 0x43)
  62                state = PSR_STATE4c;
  63        else if (raw_state == 0x44)
  64                state = PSR_STATE4d;
  65        else if (raw_state == 0x50)
  66                state = PSR_STATE5;
  67        else if (raw_state == 0x51)
  68                state = PSR_STATE5a;
  69        else if (raw_state == 0x52)
  70                state = PSR_STATE5b;
  71        else if (raw_state == 0x53)
  72                state = PSR_STATE5c;
  73
  74        return state;
  75}
  76
  77/*
  78 * Get PSR state from firmware.
  79 */
  80static void dmub_psr_get_state(struct dmub_psr *dmub, enum dc_psr_state *state)
  81{
  82        struct dmub_srv *srv = dmub->ctx->dmub_srv->dmub;
  83        uint32_t raw_state;
  84
  85        // Send gpint command and wait for ack
  86        dmub_srv_send_gpint_command(srv, DMUB_GPINT__GET_PSR_STATE, 0, 30);
  87
  88        dmub_srv_get_gpint_response(srv, &raw_state);
  89
  90        *state = convert_psr_state(raw_state);
  91}
  92
  93/*
  94 * Set PSR version.
  95 */
  96static bool dmub_psr_set_version(struct dmub_psr *dmub, struct dc_stream_state *stream)
  97{
  98        union dmub_rb_cmd cmd;
  99        struct dc_context *dc = dmub->ctx;
 100
 101        if (stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED)
 102                return false;
 103
 104        memset(&cmd, 0, sizeof(cmd));
 105        cmd.psr_set_version.header.type = DMUB_CMD__PSR;
 106        cmd.psr_set_version.header.sub_type = DMUB_CMD__PSR_SET_VERSION;
 107        switch (stream->link->psr_settings.psr_version) {
 108        case DC_PSR_VERSION_1:
 109                cmd.psr_set_version.psr_set_version_data.version = PSR_VERSION_1;
 110                break;
 111        case DC_PSR_VERSION_UNSUPPORTED:
 112        default:
 113                cmd.psr_set_version.psr_set_version_data.version = PSR_VERSION_UNSUPPORTED;
 114                break;
 115        }
 116        cmd.psr_set_version.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_version_data);
 117
 118        dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
 119        dc_dmub_srv_cmd_execute(dc->dmub_srv);
 120        dc_dmub_srv_wait_idle(dc->dmub_srv);
 121
 122        return true;
 123}
 124
 125/*
 126 * Enable/Disable PSR.
 127 */
 128static void dmub_psr_enable(struct dmub_psr *dmub, bool enable, bool wait)
 129{
 130        union dmub_rb_cmd cmd;
 131        struct dc_context *dc = dmub->ctx;
 132        uint32_t retry_count;
 133        enum dc_psr_state state = PSR_STATE0;
 134
 135        memset(&cmd, 0, sizeof(cmd));
 136        cmd.psr_enable.header.type = DMUB_CMD__PSR;
 137
 138        if (enable)
 139                cmd.psr_enable.header.sub_type = DMUB_CMD__PSR_ENABLE;
 140        else
 141                cmd.psr_enable.header.sub_type = DMUB_CMD__PSR_DISABLE;
 142
 143        cmd.psr_enable.header.payload_bytes = 0; // Send header only
 144
 145        dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
 146        dc_dmub_srv_cmd_execute(dc->dmub_srv);
 147        dc_dmub_srv_wait_idle(dc->dmub_srv);
 148
 149        /* Below loops 1000 x 500us = 500 ms.
 150         *  Exit PSR may need to wait 1-2 frames to power up. Timeout after at
 151         *  least a few frames. Should never hit the max retry assert below.
 152         */
 153        if (wait) {
 154                for (retry_count = 0; retry_count <= 1000; retry_count++) {
 155                        dmub_psr_get_state(dmub, &state);
 156
 157                        if (enable) {
 158                                if (state != PSR_STATE0)
 159                                        break;
 160                        } else {
 161                                if (state == PSR_STATE0)
 162                                        break;
 163                        }
 164
 165                        udelay(500);
 166                }
 167
 168                /* assert if max retry hit */
 169                if (retry_count >= 1000)
 170                        ASSERT(0);
 171        }
 172}
 173
 174/*
 175 * Set PSR level.
 176 */
 177static void dmub_psr_set_level(struct dmub_psr *dmub, uint16_t psr_level)
 178{
 179        union dmub_rb_cmd cmd;
 180        enum dc_psr_state state = PSR_STATE0;
 181        struct dc_context *dc = dmub->ctx;
 182
 183        dmub_psr_get_state(dmub, &state);
 184
 185        if (state == PSR_STATE0)
 186                return;
 187
 188        memset(&cmd, 0, sizeof(cmd));
 189        cmd.psr_set_level.header.type = DMUB_CMD__PSR;
 190        cmd.psr_set_level.header.sub_type = DMUB_CMD__PSR_SET_LEVEL;
 191        cmd.psr_set_level.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_level_data);
 192        cmd.psr_set_level.psr_set_level_data.psr_level = psr_level;
 193
 194        dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
 195        dc_dmub_srv_cmd_execute(dc->dmub_srv);
 196        dc_dmub_srv_wait_idle(dc->dmub_srv);
 197}
 198
 199/*
 200 * Setup PSR by programming phy registers and sending psr hw context values to firmware.
 201 */
 202static bool dmub_psr_copy_settings(struct dmub_psr *dmub,
 203                struct dc_link *link,
 204                struct psr_context *psr_context)
 205{
 206        union dmub_rb_cmd cmd;
 207        struct dc_context *dc = dmub->ctx;
 208        struct dmub_cmd_psr_copy_settings_data *copy_settings_data
 209                = &cmd.psr_copy_settings.psr_copy_settings_data;
 210        struct pipe_ctx *pipe_ctx = NULL;
 211        struct resource_context *res_ctx = &link->ctx->dc->current_state->res_ctx;
 212        int i = 0;
 213
 214        for (i = 0; i < MAX_PIPES; i++) {
 215                if (res_ctx->pipe_ctx[i].stream &&
 216                    res_ctx->pipe_ctx[i].stream->link == link &&
 217                    res_ctx->pipe_ctx[i].stream->link->connector_signal == SIGNAL_TYPE_EDP) {
 218                        pipe_ctx = &res_ctx->pipe_ctx[i];
 219                        break;
 220                }
 221        }
 222
 223        if (!pipe_ctx)
 224                return false;
 225
 226        // First, set the psr version
 227        if (!dmub_psr_set_version(dmub, pipe_ctx->stream))
 228                return false;
 229
 230        // Program DP DPHY fast training registers
 231        link->link_enc->funcs->psr_program_dp_dphy_fast_training(link->link_enc,
 232                        psr_context->psrExitLinkTrainingRequired);
 233
 234        // Program DP_SEC_CNTL1 register to set transmission GPS0 line num and priority to high
 235        link->link_enc->funcs->psr_program_secondary_packet(link->link_enc,
 236                        psr_context->sdpTransmitLineNumDeadline);
 237
 238        memset(&cmd, 0, sizeof(cmd));
 239        cmd.psr_copy_settings.header.type = DMUB_CMD__PSR;
 240        cmd.psr_copy_settings.header.sub_type = DMUB_CMD__PSR_COPY_SETTINGS;
 241        cmd.psr_copy_settings.header.payload_bytes = sizeof(struct dmub_cmd_psr_copy_settings_data);
 242
 243        // Hw insts
 244        copy_settings_data->dpphy_inst                          = psr_context->transmitterId;
 245        copy_settings_data->aux_inst                            = psr_context->channel;
 246        copy_settings_data->digfe_inst                          = psr_context->engineId;
 247        copy_settings_data->digbe_inst                          = psr_context->transmitterId;
 248
 249        copy_settings_data->mpcc_inst                           = pipe_ctx->plane_res.mpcc_inst;
 250
 251        if (pipe_ctx->plane_res.dpp)
 252                copy_settings_data->dpp_inst                    = pipe_ctx->plane_res.dpp->inst;
 253        else
 254                copy_settings_data->dpp_inst                    = 0;
 255        if (pipe_ctx->stream_res.opp)
 256                copy_settings_data->opp_inst                    = pipe_ctx->stream_res.opp->inst;
 257        else
 258                copy_settings_data->opp_inst                    = 0;
 259        if (pipe_ctx->stream_res.tg)
 260                copy_settings_data->otg_inst                    = pipe_ctx->stream_res.tg->inst;
 261        else
 262                copy_settings_data->otg_inst                    = 0;
 263
 264        // Misc
 265        copy_settings_data->psr_level                           = psr_context->psr_level.u32all;
 266        copy_settings_data->smu_optimizations_en                = psr_context->allow_smu_optimizations;
 267        copy_settings_data->multi_disp_optimizations_en = psr_context->allow_multi_disp_optimizations;
 268        copy_settings_data->frame_delay                         = psr_context->frame_delay;
 269        copy_settings_data->frame_cap_ind                       = psr_context->psrFrameCaptureIndicationReq;
 270        copy_settings_data->init_sdp_deadline                   = psr_context->sdpTransmitLineNumDeadline;
 271        copy_settings_data->debug.u32All = 0;
 272        copy_settings_data->debug.bitfields.visual_confirm      = dc->dc->debug.visual_confirm == VISUAL_CONFIRM_PSR ?
 273                                                                        true : false;
 274        copy_settings_data->debug.bitfields.use_hw_lock_mgr             = 1;
 275
 276        dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
 277        dc_dmub_srv_cmd_execute(dc->dmub_srv);
 278        dc_dmub_srv_wait_idle(dc->dmub_srv);
 279
 280        return true;
 281}
 282
 283/*
 284 * Send command to PSR to force static ENTER and ignore all state changes until exit
 285 */
 286static void dmub_psr_force_static(struct dmub_psr *dmub)
 287{
 288        union dmub_rb_cmd cmd;
 289        struct dc_context *dc = dmub->ctx;
 290
 291        memset(&cmd, 0, sizeof(cmd));
 292        cmd.psr_force_static.header.type = DMUB_CMD__PSR;
 293        cmd.psr_force_static.header.sub_type = DMUB_CMD__PSR_FORCE_STATIC;
 294        cmd.psr_enable.header.payload_bytes = 0;
 295
 296        dc_dmub_srv_cmd_queue(dc->dmub_srv, &cmd);
 297        dc_dmub_srv_cmd_execute(dc->dmub_srv);
 298        dc_dmub_srv_wait_idle(dc->dmub_srv);
 299}
 300
 301/*
 302 * Get PSR residency from firmware.
 303 */
 304static void dmub_psr_get_residency(struct dmub_psr *dmub, uint32_t *residency)
 305{
 306        struct dmub_srv *srv = dmub->ctx->dmub_srv->dmub;
 307
 308        // Send gpint command and wait for ack
 309        dmub_srv_send_gpint_command(srv, DMUB_GPINT__PSR_RESIDENCY, 0, 30);
 310
 311        dmub_srv_get_gpint_response(srv, residency);
 312}
 313
 314static const struct dmub_psr_funcs psr_funcs = {
 315        .psr_copy_settings              = dmub_psr_copy_settings,
 316        .psr_enable                     = dmub_psr_enable,
 317        .psr_get_state                  = dmub_psr_get_state,
 318        .psr_set_level                  = dmub_psr_set_level,
 319        .psr_force_static               = dmub_psr_force_static,
 320        .psr_get_residency              = dmub_psr_get_residency,
 321};
 322
 323/*
 324 * Construct PSR object.
 325 */
 326static void dmub_psr_construct(struct dmub_psr *psr, struct dc_context *ctx)
 327{
 328        psr->ctx = ctx;
 329        psr->funcs = &psr_funcs;
 330}
 331
 332/*
 333 * Allocate and initialize PSR object.
 334 */
 335struct dmub_psr *dmub_psr_create(struct dc_context *ctx)
 336{
 337        struct dmub_psr *psr = kzalloc(sizeof(struct dmub_psr), GFP_KERNEL);
 338
 339        if (psr == NULL) {
 340                BREAK_TO_DEBUGGER();
 341                return NULL;
 342        }
 343
 344        dmub_psr_construct(psr, ctx);
 345
 346        return psr;
 347}
 348
 349/*
 350 * Deallocate PSR object.
 351 */
 352void dmub_psr_destroy(struct dmub_psr **dmub)
 353{
 354        kfree(*dmub);
 355        *dmub = NULL;
 356}
 357