linux/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c
<<
>>
Prefs
   1/*
   2 * Copyright 2012-15 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 "reg_helper.h"
  27#include "dcn10_mpc.h"
  28
  29#define REG(reg)\
  30        mpc10->mpc_regs->reg
  31
  32#define CTX \
  33        mpc10->base.ctx
  34
  35#undef FN
  36#define FN(reg_name, field_name) \
  37        mpc10->mpc_shift->field_name, mpc10->mpc_mask->field_name
  38
  39
  40void mpc1_set_bg_color(struct mpc *mpc,
  41                struct tg_color *bg_color,
  42                int mpcc_id)
  43{
  44        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  45        struct mpcc *bottommost_mpcc = mpc1_get_mpcc(mpc, mpcc_id);
  46        uint32_t bg_r_cr, bg_g_y, bg_b_cb;
  47
  48        bottommost_mpcc->blnd_cfg.black_color = *bg_color;
  49
  50        /* find bottommost mpcc. */
  51        while (bottommost_mpcc->mpcc_bot) {
  52                bottommost_mpcc = bottommost_mpcc->mpcc_bot;
  53        }
  54
  55        /* mpc color is 12 bit.  tg_color is 10 bit */
  56        /* todo: might want to use 16 bit to represent color and have each
  57         * hw block translate to correct color depth.
  58         */
  59        bg_r_cr = bg_color->color_r_cr << 2;
  60        bg_g_y = bg_color->color_g_y << 2;
  61        bg_b_cb = bg_color->color_b_cb << 2;
  62
  63        REG_SET(MPCC_BG_R_CR[bottommost_mpcc->mpcc_id], 0,
  64                        MPCC_BG_R_CR, bg_r_cr);
  65        REG_SET(MPCC_BG_G_Y[bottommost_mpcc->mpcc_id], 0,
  66                        MPCC_BG_G_Y, bg_g_y);
  67        REG_SET(MPCC_BG_B_CB[bottommost_mpcc->mpcc_id], 0,
  68                        MPCC_BG_B_CB, bg_b_cb);
  69}
  70
  71static void mpc1_update_blending(
  72        struct mpc *mpc,
  73        struct mpcc_blnd_cfg *blnd_cfg,
  74        int mpcc_id)
  75{
  76        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  77        struct mpcc *mpcc = mpc1_get_mpcc(mpc, mpcc_id);
  78
  79        REG_UPDATE_5(MPCC_CONTROL[mpcc_id],
  80                        MPCC_ALPHA_BLND_MODE,           blnd_cfg->alpha_mode,
  81                        MPCC_ALPHA_MULTIPLIED_MODE,     blnd_cfg->pre_multiplied_alpha,
  82                        MPCC_BLND_ACTIVE_OVERLAP_ONLY,  blnd_cfg->overlap_only,
  83                        MPCC_GLOBAL_ALPHA,              blnd_cfg->global_alpha,
  84                        MPCC_GLOBAL_GAIN,               blnd_cfg->global_gain);
  85
  86        mpcc->blnd_cfg = *blnd_cfg;
  87}
  88
  89void mpc1_update_stereo_mix(
  90        struct mpc *mpc,
  91        struct mpcc_sm_cfg *sm_cfg,
  92        int mpcc_id)
  93{
  94        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  95
  96        REG_UPDATE_6(MPCC_SM_CONTROL[mpcc_id],
  97                        MPCC_SM_EN,                     sm_cfg->enable,
  98                        MPCC_SM_MODE,                   sm_cfg->sm_mode,
  99                        MPCC_SM_FRAME_ALT,              sm_cfg->frame_alt,
 100                        MPCC_SM_FIELD_ALT,              sm_cfg->field_alt,
 101                        MPCC_SM_FORCE_NEXT_FRAME_POL,   sm_cfg->force_next_frame_porlarity,
 102                        MPCC_SM_FORCE_NEXT_TOP_POL,     sm_cfg->force_next_field_polarity);
 103}
 104void mpc1_assert_idle_mpcc(struct mpc *mpc, int id)
 105{
 106        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
 107
 108        ASSERT(!(mpc10->mpcc_in_use_mask & 1 << id));
 109        REG_WAIT(MPCC_STATUS[id],
 110                        MPCC_IDLE, 1,
 111                        1, 100000);
 112}
 113
 114struct mpcc *mpc1_get_mpcc(struct mpc *mpc, int mpcc_id)
 115{
 116        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
 117
 118        ASSERT(mpcc_id < mpc10->num_mpcc);
 119        return &(mpc->mpcc_array[mpcc_id]);
 120}
 121
 122struct mpcc *mpc1_get_mpcc_for_dpp(struct mpc_tree *tree, int dpp_id)
 123{
 124        struct mpcc *tmp_mpcc = tree->opp_list;
 125
 126        while (tmp_mpcc != NULL) {
 127                if (tmp_mpcc->dpp_id == dpp_id)
 128                        return tmp_mpcc;
 129                tmp_mpcc = tmp_mpcc->mpcc_bot;
 130        }
 131        return NULL;
 132}
 133
 134bool mpc1_is_mpcc_idle(struct mpc *mpc, int mpcc_id)
 135{
 136        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
 137        unsigned int top_sel;
 138        unsigned int opp_id;
 139        unsigned int idle;
 140
 141        REG_GET(MPCC_TOP_SEL[mpcc_id], MPCC_TOP_SEL, &top_sel);
 142        REG_GET(MPCC_OPP_ID[mpcc_id],  MPCC_OPP_ID, &opp_id);
 143        REG_GET(MPCC_STATUS[mpcc_id],  MPCC_IDLE,   &idle);
 144        if (top_sel == 0xf && opp_id == 0xf && idle)
 145                return true;
 146        else
 147                return false;
 148}
 149
 150void mpc1_assert_mpcc_idle_before_connect(struct mpc *mpc, int mpcc_id)
 151{
 152        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
 153        unsigned int top_sel, mpc_busy, mpc_idle;
 154
 155        REG_GET(MPCC_TOP_SEL[mpcc_id],
 156                        MPCC_TOP_SEL, &top_sel);
 157
 158        if (top_sel == 0xf) {
 159                REG_GET_2(MPCC_STATUS[mpcc_id],
 160                                MPCC_BUSY, &mpc_busy,
 161                                MPCC_IDLE, &mpc_idle);
 162
 163                ASSERT(mpc_busy == 0);
 164                ASSERT(mpc_idle == 1);
 165        }
 166}
 167
 168/*
 169 * Insert DPP into MPC tree based on specified blending position.
 170 * Only used for planes that are part of blending chain for OPP output
 171 *
 172 * Parameters:
 173 * [in/out] mpc         - MPC context.
 174 * [in/out] tree        - MPC tree structure that plane will be added to.
 175 * [in] blnd_cfg        - MPCC blending configuration for the new blending layer.
 176 * [in] sm_cfg          - MPCC stereo mix configuration for the new blending layer.
 177 *                        stereo mix must disable for the very bottom layer of the tree config.
 178 * [in] insert_above_mpcc - Insert new plane above this MPCC.  If NULL, insert as bottom plane.
 179 * [in] dpp_id          - DPP instance for the plane to be added.
 180 * [in] mpcc_id         - The MPCC physical instance to use for blending.
 181 *
 182 * Return:  struct mpcc* - MPCC that was added.
 183 */
 184struct mpcc *mpc1_insert_plane(
 185        struct mpc *mpc,
 186        struct mpc_tree *tree,
 187        struct mpcc_blnd_cfg *blnd_cfg,
 188        struct mpcc_sm_cfg *sm_cfg,
 189        struct mpcc *insert_above_mpcc,
 190        int dpp_id,
 191        int mpcc_id)
 192{
 193        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
 194        struct mpcc *new_mpcc = NULL;
 195
 196        /* sanity check parameters */
 197        ASSERT(mpcc_id < mpc10->num_mpcc);
 198        ASSERT(!(mpc10->mpcc_in_use_mask & 1 << mpcc_id));
 199
 200        if (insert_above_mpcc) {
 201                /* check insert_above_mpcc exist in tree->opp_list */
 202                struct mpcc *temp_mpcc = tree->opp_list;
 203
 204                while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc)
 205                        temp_mpcc = temp_mpcc->mpcc_bot;
 206                if (temp_mpcc == NULL)
 207                        return NULL;
 208        }
 209
 210        /* Get and update MPCC struct parameters */
 211        new_mpcc = mpc1_get_mpcc(mpc, mpcc_id);
 212        new_mpcc->dpp_id = dpp_id;
 213
 214        /* program mux and MPCC_MODE */
 215        if (insert_above_mpcc) {
 216                new_mpcc->mpcc_bot = insert_above_mpcc;
 217                REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, insert_above_mpcc->mpcc_id);
 218                REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING);
 219        } else {
 220                new_mpcc->mpcc_bot = NULL;
 221                REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
 222                REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_ONLY);
 223        }
 224        REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, dpp_id);
 225        REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, tree->opp_id);
 226
 227        /* Configure VUPDATE lock set for this MPCC to map to the OPP */
 228        REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, tree->opp_id);
 229
 230        /* update mpc tree mux setting */
 231        if (tree->opp_list == insert_above_mpcc) {
 232                /* insert the toppest mpcc */
 233                tree->opp_list = new_mpcc;
 234                REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, mpcc_id);
 235        } else {
 236                /* find insert position */
 237                struct mpcc *temp_mpcc = tree->opp_list;
 238
 239                while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc)
 240                        temp_mpcc = temp_mpcc->mpcc_bot;
 241                if (temp_mpcc && temp_mpcc->mpcc_bot == insert_above_mpcc) {
 242                        REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0, MPCC_BOT_SEL, mpcc_id);
 243                        temp_mpcc->mpcc_bot = new_mpcc;
 244                        if (!insert_above_mpcc)
 245                                REG_UPDATE(MPCC_CONTROL[temp_mpcc->mpcc_id],
 246                                                MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING);
 247                }
 248        }
 249
 250        /* update the blending configuration */
 251        mpc->funcs->update_blending(mpc, blnd_cfg, mpcc_id);
 252
 253        /* update the stereo mix settings, if provided */
 254        if (sm_cfg != NULL) {
 255                new_mpcc->sm_cfg = *sm_cfg;
 256                mpc1_update_stereo_mix(mpc, sm_cfg, mpcc_id);
 257        }
 258
 259        /* mark this mpcc as in use */
 260        mpc10->mpcc_in_use_mask |= 1 << mpcc_id;
 261
 262        return new_mpcc;
 263}
 264
 265/*
 266 * Remove a specified MPCC from the MPC tree.
 267 *
 268 * Parameters:
 269 * [in/out] mpc         - MPC context.
 270 * [in/out] tree        - MPC tree structure that plane will be removed from.
 271 * [in/out] mpcc        - MPCC to be removed from tree.
 272 *
 273 * Return:  void
 274 */
 275void mpc1_remove_mpcc(
 276        struct mpc *mpc,
 277        struct mpc_tree *tree,
 278        struct mpcc *mpcc_to_remove)
 279{
 280        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
 281        bool found = false;
 282        int mpcc_id = mpcc_to_remove->mpcc_id;
 283
 284        if (tree->opp_list == mpcc_to_remove) {
 285                found = true;
 286                /* remove MPCC from top of tree */
 287                if (mpcc_to_remove->mpcc_bot) {
 288                        /* set the next MPCC in list to be the top MPCC */
 289                        tree->opp_list = mpcc_to_remove->mpcc_bot;
 290                        REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, tree->opp_list->mpcc_id);
 291                } else {
 292                        /* there are no other MPCC is list */
 293                        tree->opp_list = NULL;
 294                        REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, 0xf);
 295                }
 296        } else {
 297                /* find mpcc to remove MPCC list */
 298                struct mpcc *temp_mpcc = tree->opp_list;
 299
 300                while (temp_mpcc && temp_mpcc->mpcc_bot != mpcc_to_remove)
 301                        temp_mpcc = temp_mpcc->mpcc_bot;
 302
 303                if (temp_mpcc && temp_mpcc->mpcc_bot == mpcc_to_remove) {
 304                        found = true;
 305                        temp_mpcc->mpcc_bot = mpcc_to_remove->mpcc_bot;
 306                        if (mpcc_to_remove->mpcc_bot) {
 307                                /* remove MPCC in middle of list */
 308                                REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0,
 309                                                MPCC_BOT_SEL, mpcc_to_remove->mpcc_bot->mpcc_id);
 310                        } else {
 311                                /* remove MPCC from bottom of list */
 312                                REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0,
 313                                                MPCC_BOT_SEL, 0xf);
 314                                REG_UPDATE(MPCC_CONTROL[temp_mpcc->mpcc_id],
 315                                                MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_PASSTHROUGH);
 316                        }
 317                }
 318        }
 319
 320        if (found) {
 321                /* turn off MPCC mux registers */
 322                REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
 323                REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
 324                REG_SET(MPCC_OPP_ID[mpcc_id],  0, MPCC_OPP_ID,  0xf);
 325                REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, 0xf);
 326
 327                /* mark this mpcc as not in use */
 328                mpc10->mpcc_in_use_mask &= ~(1 << mpcc_id);
 329                mpcc_to_remove->dpp_id = 0xf;
 330                mpcc_to_remove->mpcc_bot = NULL;
 331        } else {
 332                /* In case of resume from S3/S4, remove mpcc from bios left over */
 333                REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
 334                REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
 335                REG_SET(MPCC_OPP_ID[mpcc_id],  0, MPCC_OPP_ID,  0xf);
 336                REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, 0xf);
 337        }
 338}
 339
 340static void mpc1_init_mpcc(struct mpcc *mpcc, int mpcc_inst)
 341{
 342        mpcc->mpcc_id = mpcc_inst;
 343        mpcc->dpp_id = 0xf;
 344        mpcc->mpcc_bot = NULL;
 345        mpcc->blnd_cfg.overlap_only = false;
 346        mpcc->blnd_cfg.global_alpha = 0xff;
 347        mpcc->blnd_cfg.global_gain = 0xff;
 348        mpcc->sm_cfg.enable = false;
 349}
 350
 351/*
 352 * Reset the MPCC HW status by disconnecting all muxes.
 353 *
 354 * Parameters:
 355 * [in/out] mpc         - MPC context.
 356 *
 357 * Return:  void
 358 */
 359void mpc1_mpc_init(struct mpc *mpc)
 360{
 361        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
 362        int mpcc_id;
 363        int opp_id;
 364
 365        mpc10->mpcc_in_use_mask = 0;
 366        for (mpcc_id = 0; mpcc_id < mpc10->num_mpcc; mpcc_id++) {
 367                REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
 368                REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
 369                REG_SET(MPCC_OPP_ID[mpcc_id],  0, MPCC_OPP_ID,  0xf);
 370                REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, 0xf);
 371
 372                mpc1_init_mpcc(&(mpc->mpcc_array[mpcc_id]), mpcc_id);
 373        }
 374
 375        for (opp_id = 0; opp_id < MAX_OPP; opp_id++) {
 376                if (REG(MUX[opp_id]))
 377                        REG_UPDATE(MUX[opp_id], MPC_OUT_MUX, 0xf);
 378        }
 379}
 380
 381void mpc1_mpc_init_single_inst(struct mpc *mpc, unsigned int mpcc_id)
 382{
 383        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
 384        int opp_id;
 385
 386        REG_GET(MPCC_OPP_ID[mpcc_id], MPCC_OPP_ID, &opp_id);
 387
 388        REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
 389        REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
 390        REG_SET(MPCC_OPP_ID[mpcc_id],  0, MPCC_OPP_ID,  0xf);
 391        REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, 0xf);
 392
 393        mpc1_init_mpcc(&(mpc->mpcc_array[mpcc_id]), mpcc_id);
 394
 395        if (opp_id < MAX_OPP && REG(MUX[opp_id]))
 396                REG_UPDATE(MUX[opp_id], MPC_OUT_MUX, 0xf);
 397}
 398
 399
 400void mpc1_init_mpcc_list_from_hw(
 401        struct mpc *mpc,
 402        struct mpc_tree *tree)
 403{
 404        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
 405        unsigned int opp_id;
 406        unsigned int top_sel;
 407        unsigned int bot_sel;
 408        unsigned int out_mux;
 409        struct mpcc *mpcc;
 410        int mpcc_id;
 411        int bot_mpcc_id;
 412
 413        REG_GET(MUX[tree->opp_id], MPC_OUT_MUX, &out_mux);
 414
 415        if (out_mux != 0xf) {
 416                for (mpcc_id = 0; mpcc_id < mpc10->num_mpcc; mpcc_id++) {
 417                        REG_GET(MPCC_OPP_ID[mpcc_id],  MPCC_OPP_ID,  &opp_id);
 418                        REG_GET(MPCC_TOP_SEL[mpcc_id], MPCC_TOP_SEL, &top_sel);
 419                        REG_GET(MPCC_BOT_SEL[mpcc_id],  MPCC_BOT_SEL, &bot_sel);
 420
 421                        if (bot_sel == mpcc_id)
 422                                bot_sel = 0xf;
 423
 424                        if ((opp_id == tree->opp_id) && (top_sel != 0xf)) {
 425                                mpcc = mpc1_get_mpcc(mpc, mpcc_id);
 426                                mpcc->dpp_id = top_sel;
 427                                mpc10->mpcc_in_use_mask |= 1 << mpcc_id;
 428
 429                                if (out_mux == mpcc_id)
 430                                        tree->opp_list = mpcc;
 431                                if (bot_sel != 0xf && bot_sel < mpc10->num_mpcc) {
 432                                        bot_mpcc_id = bot_sel;
 433                                        REG_GET(MPCC_OPP_ID[bot_mpcc_id],  MPCC_OPP_ID,  &opp_id);
 434                                        REG_GET(MPCC_TOP_SEL[bot_mpcc_id], MPCC_TOP_SEL, &top_sel);
 435                                        if ((opp_id == tree->opp_id) && (top_sel != 0xf)) {
 436                                                struct mpcc *mpcc_bottom = mpc1_get_mpcc(mpc, bot_mpcc_id);
 437
 438                                                mpcc->mpcc_bot = mpcc_bottom;
 439                                        }
 440                                }
 441                        }
 442                }
 443        }
 444}
 445
 446void mpc1_read_mpcc_state(
 447                struct mpc *mpc,
 448                int mpcc_inst,
 449                struct mpcc_state *s)
 450{
 451        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
 452
 453        REG_GET(MPCC_OPP_ID[mpcc_inst], MPCC_OPP_ID, &s->opp_id);
 454        REG_GET(MPCC_TOP_SEL[mpcc_inst], MPCC_TOP_SEL, &s->dpp_id);
 455        REG_GET(MPCC_BOT_SEL[mpcc_inst], MPCC_BOT_SEL, &s->bot_mpcc_id);
 456        REG_GET_4(MPCC_CONTROL[mpcc_inst], MPCC_MODE, &s->mode,
 457                        MPCC_ALPHA_BLND_MODE, &s->alpha_mode,
 458                        MPCC_ALPHA_MULTIPLIED_MODE, &s->pre_multiplied_alpha,
 459                        MPCC_BLND_ACTIVE_OVERLAP_ONLY, &s->overlap_only);
 460        REG_GET_2(MPCC_STATUS[mpcc_inst], MPCC_IDLE, &s->idle,
 461                        MPCC_BUSY, &s->busy);
 462}
 463
 464void mpc1_cursor_lock(struct mpc *mpc, int opp_id, bool lock)
 465{
 466        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
 467
 468        REG_SET(CUR[opp_id], 0, CUR_VUPDATE_LOCK_SET, lock ? 1 : 0);
 469}
 470
 471unsigned int mpc1_get_mpc_out_mux(struct mpc *mpc, int opp_id)
 472{
 473        struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
 474        uint32_t val = 0xf;
 475
 476        if (opp_id < MAX_OPP && REG(MUX[opp_id]))
 477                REG_GET(MUX[opp_id], MPC_OUT_MUX, &val);
 478
 479        return val;
 480}
 481
 482static const struct mpc_funcs dcn10_mpc_funcs = {
 483        .read_mpcc_state = mpc1_read_mpcc_state,
 484        .insert_plane = mpc1_insert_plane,
 485        .remove_mpcc = mpc1_remove_mpcc,
 486        .mpc_init = mpc1_mpc_init,
 487        .mpc_init_single_inst = mpc1_mpc_init_single_inst,
 488        .get_mpcc_for_dpp = mpc1_get_mpcc_for_dpp,
 489        .wait_for_idle = mpc1_assert_idle_mpcc,
 490        .assert_mpcc_idle_before_connect = mpc1_assert_mpcc_idle_before_connect,
 491        .init_mpcc_list_from_hw = mpc1_init_mpcc_list_from_hw,
 492        .update_blending = mpc1_update_blending,
 493        .cursor_lock = mpc1_cursor_lock,
 494        .set_denorm = NULL,
 495        .set_denorm_clamp = NULL,
 496        .set_output_csc = NULL,
 497        .set_output_gamma = NULL,
 498        .get_mpc_out_mux = mpc1_get_mpc_out_mux,
 499        .set_bg_color = mpc1_set_bg_color,
 500};
 501
 502void dcn10_mpc_construct(struct dcn10_mpc *mpc10,
 503        struct dc_context *ctx,
 504        const struct dcn_mpc_registers *mpc_regs,
 505        const struct dcn_mpc_shift *mpc_shift,
 506        const struct dcn_mpc_mask *mpc_mask,
 507        int num_mpcc)
 508{
 509        int i;
 510
 511        mpc10->base.ctx = ctx;
 512
 513        mpc10->base.funcs = &dcn10_mpc_funcs;
 514
 515        mpc10->mpc_regs = mpc_regs;
 516        mpc10->mpc_shift = mpc_shift;
 517        mpc10->mpc_mask = mpc_mask;
 518
 519        mpc10->mpcc_in_use_mask = 0;
 520        mpc10->num_mpcc = num_mpcc;
 521
 522        for (i = 0; i < MAX_MPCC; i++)
 523                mpc1_init_mpcc(&mpc10->base.mpcc_array[i], i);
 524}
 525
 526