Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012-15 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 
0026 #include "reg_helper.h"
0027 #include "dcn10_mpc.h"
0028 
0029 #define REG(reg)\
0030     mpc10->mpc_regs->reg
0031 
0032 #define CTX \
0033     mpc10->base.ctx
0034 
0035 #undef FN
0036 #define FN(reg_name, field_name) \
0037     mpc10->mpc_shift->field_name, mpc10->mpc_mask->field_name
0038 
0039 
0040 void mpc1_set_bg_color(struct mpc *mpc,
0041         struct tg_color *bg_color,
0042         int mpcc_id)
0043 {
0044     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0045     struct mpcc *bottommost_mpcc = mpc1_get_mpcc(mpc, mpcc_id);
0046     uint32_t bg_r_cr, bg_g_y, bg_b_cb;
0047 
0048     bottommost_mpcc->blnd_cfg.black_color = *bg_color;
0049 
0050     /* find bottommost mpcc. */
0051     while (bottommost_mpcc->mpcc_bot) {
0052         /* avoid circular linked link */
0053         ASSERT(bottommost_mpcc != bottommost_mpcc->mpcc_bot);
0054         if (bottommost_mpcc == bottommost_mpcc->mpcc_bot)
0055             break;
0056 
0057         bottommost_mpcc = bottommost_mpcc->mpcc_bot;
0058     }
0059 
0060     /* mpc color is 12 bit.  tg_color is 10 bit */
0061     /* todo: might want to use 16 bit to represent color and have each
0062      * hw block translate to correct color depth.
0063      */
0064     bg_r_cr = bg_color->color_r_cr << 2;
0065     bg_g_y = bg_color->color_g_y << 2;
0066     bg_b_cb = bg_color->color_b_cb << 2;
0067 
0068     REG_SET(MPCC_BG_R_CR[bottommost_mpcc->mpcc_id], 0,
0069             MPCC_BG_R_CR, bg_r_cr);
0070     REG_SET(MPCC_BG_G_Y[bottommost_mpcc->mpcc_id], 0,
0071             MPCC_BG_G_Y, bg_g_y);
0072     REG_SET(MPCC_BG_B_CB[bottommost_mpcc->mpcc_id], 0,
0073             MPCC_BG_B_CB, bg_b_cb);
0074 }
0075 
0076 static void mpc1_update_blending(
0077     struct mpc *mpc,
0078     struct mpcc_blnd_cfg *blnd_cfg,
0079     int mpcc_id)
0080 {
0081     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0082     struct mpcc *mpcc = mpc1_get_mpcc(mpc, mpcc_id);
0083 
0084     REG_UPDATE_5(MPCC_CONTROL[mpcc_id],
0085             MPCC_ALPHA_BLND_MODE,       blnd_cfg->alpha_mode,
0086             MPCC_ALPHA_MULTIPLIED_MODE, blnd_cfg->pre_multiplied_alpha,
0087             MPCC_BLND_ACTIVE_OVERLAP_ONLY,  blnd_cfg->overlap_only,
0088             MPCC_GLOBAL_ALPHA,      blnd_cfg->global_alpha,
0089             MPCC_GLOBAL_GAIN,       blnd_cfg->global_gain);
0090 
0091     mpcc->blnd_cfg = *blnd_cfg;
0092 }
0093 
0094 void mpc1_update_stereo_mix(
0095     struct mpc *mpc,
0096     struct mpcc_sm_cfg *sm_cfg,
0097     int mpcc_id)
0098 {
0099     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0100 
0101     REG_UPDATE_6(MPCC_SM_CONTROL[mpcc_id],
0102             MPCC_SM_EN,         sm_cfg->enable,
0103             MPCC_SM_MODE,           sm_cfg->sm_mode,
0104             MPCC_SM_FRAME_ALT,      sm_cfg->frame_alt,
0105             MPCC_SM_FIELD_ALT,      sm_cfg->field_alt,
0106             MPCC_SM_FORCE_NEXT_FRAME_POL,   sm_cfg->force_next_frame_porlarity,
0107             MPCC_SM_FORCE_NEXT_TOP_POL, sm_cfg->force_next_field_polarity);
0108 }
0109 void mpc1_assert_idle_mpcc(struct mpc *mpc, int id)
0110 {
0111     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0112 
0113     ASSERT(!(mpc10->mpcc_in_use_mask & 1 << id));
0114     REG_WAIT(MPCC_STATUS[id],
0115             MPCC_IDLE, 1,
0116             1, 100000);
0117 }
0118 
0119 struct mpcc *mpc1_get_mpcc(struct mpc *mpc, int mpcc_id)
0120 {
0121     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0122 
0123     ASSERT(mpcc_id < mpc10->num_mpcc);
0124     return &(mpc->mpcc_array[mpcc_id]);
0125 }
0126 
0127 struct mpcc *mpc1_get_mpcc_for_dpp(struct mpc_tree *tree, int dpp_id)
0128 {
0129     struct mpcc *tmp_mpcc = tree->opp_list;
0130 
0131     while (tmp_mpcc != NULL) {
0132         if (tmp_mpcc->dpp_id == dpp_id)
0133             return tmp_mpcc;
0134 
0135         /* avoid circular linked list */
0136         ASSERT(tmp_mpcc != tmp_mpcc->mpcc_bot);
0137         if (tmp_mpcc == tmp_mpcc->mpcc_bot)
0138             break;
0139 
0140         tmp_mpcc = tmp_mpcc->mpcc_bot;
0141     }
0142     return NULL;
0143 }
0144 
0145 bool mpc1_is_mpcc_idle(struct mpc *mpc, int mpcc_id)
0146 {
0147     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0148     unsigned int top_sel;
0149     unsigned int opp_id;
0150     unsigned int idle;
0151 
0152     REG_GET(MPCC_TOP_SEL[mpcc_id], MPCC_TOP_SEL, &top_sel);
0153     REG_GET(MPCC_OPP_ID[mpcc_id],  MPCC_OPP_ID, &opp_id);
0154     REG_GET(MPCC_STATUS[mpcc_id],  MPCC_IDLE,   &idle);
0155     if (top_sel == 0xf && opp_id == 0xf && idle)
0156         return true;
0157     else
0158         return false;
0159 }
0160 
0161 void mpc1_assert_mpcc_idle_before_connect(struct mpc *mpc, int mpcc_id)
0162 {
0163     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0164     unsigned int top_sel, mpc_busy, mpc_idle;
0165 
0166     REG_GET(MPCC_TOP_SEL[mpcc_id],
0167             MPCC_TOP_SEL, &top_sel);
0168 
0169     if (top_sel == 0xf) {
0170         REG_GET_2(MPCC_STATUS[mpcc_id],
0171                 MPCC_BUSY, &mpc_busy,
0172                 MPCC_IDLE, &mpc_idle);
0173 
0174         ASSERT(mpc_busy == 0);
0175         ASSERT(mpc_idle == 1);
0176     }
0177 }
0178 
0179 /*
0180  * Insert DPP into MPC tree based on specified blending position.
0181  * Only used for planes that are part of blending chain for OPP output
0182  *
0183  * Parameters:
0184  * [in/out] mpc     - MPC context.
0185  * [in/out] tree    - MPC tree structure that plane will be added to.
0186  * [in] blnd_cfg    - MPCC blending configuration for the new blending layer.
0187  * [in] sm_cfg      - MPCC stereo mix configuration for the new blending layer.
0188  *            stereo mix must disable for the very bottom layer of the tree config.
0189  * [in] insert_above_mpcc - Insert new plane above this MPCC.  If NULL, insert as bottom plane.
0190  * [in] dpp_id      - DPP instance for the plane to be added.
0191  * [in] mpcc_id     - The MPCC physical instance to use for blending.
0192  *
0193  * Return:  struct mpcc* - MPCC that was added.
0194  */
0195 struct mpcc *mpc1_insert_plane(
0196     struct mpc *mpc,
0197     struct mpc_tree *tree,
0198     struct mpcc_blnd_cfg *blnd_cfg,
0199     struct mpcc_sm_cfg *sm_cfg,
0200     struct mpcc *insert_above_mpcc,
0201     int dpp_id,
0202     int mpcc_id)
0203 {
0204     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0205     struct mpcc *new_mpcc = NULL;
0206 
0207     /* sanity check parameters */
0208     ASSERT(mpcc_id < mpc10->num_mpcc);
0209     ASSERT(!(mpc10->mpcc_in_use_mask & 1 << mpcc_id));
0210 
0211     if (insert_above_mpcc) {
0212         /* check insert_above_mpcc exist in tree->opp_list */
0213         struct mpcc *temp_mpcc = tree->opp_list;
0214 
0215         while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc)
0216             temp_mpcc = temp_mpcc->mpcc_bot;
0217         if (temp_mpcc == NULL)
0218             return NULL;
0219     }
0220 
0221     /* Get and update MPCC struct parameters */
0222     new_mpcc = mpc1_get_mpcc(mpc, mpcc_id);
0223     new_mpcc->dpp_id = dpp_id;
0224 
0225     /* program mux and MPCC_MODE */
0226     if (insert_above_mpcc) {
0227         new_mpcc->mpcc_bot = insert_above_mpcc;
0228         REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, insert_above_mpcc->mpcc_id);
0229         REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING);
0230     } else {
0231         new_mpcc->mpcc_bot = NULL;
0232         REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
0233         REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_ONLY);
0234     }
0235     REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, dpp_id);
0236     REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, tree->opp_id);
0237 
0238     /* Configure VUPDATE lock set for this MPCC to map to the OPP */
0239     REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, tree->opp_id);
0240 
0241     /* update mpc tree mux setting */
0242     if (tree->opp_list == insert_above_mpcc) {
0243         /* insert the toppest mpcc */
0244         tree->opp_list = new_mpcc;
0245         REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, mpcc_id);
0246     } else {
0247         /* find insert position */
0248         struct mpcc *temp_mpcc = tree->opp_list;
0249 
0250         while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc)
0251             temp_mpcc = temp_mpcc->mpcc_bot;
0252         if (temp_mpcc && temp_mpcc->mpcc_bot == insert_above_mpcc) {
0253             REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0, MPCC_BOT_SEL, mpcc_id);
0254             temp_mpcc->mpcc_bot = new_mpcc;
0255             if (!insert_above_mpcc)
0256                 REG_UPDATE(MPCC_CONTROL[temp_mpcc->mpcc_id],
0257                         MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING);
0258         }
0259     }
0260 
0261     /* update the blending configuration */
0262     mpc->funcs->update_blending(mpc, blnd_cfg, mpcc_id);
0263 
0264     /* update the stereo mix settings, if provided */
0265     if (sm_cfg != NULL) {
0266         new_mpcc->sm_cfg = *sm_cfg;
0267         mpc1_update_stereo_mix(mpc, sm_cfg, mpcc_id);
0268     }
0269 
0270     /* mark this mpcc as in use */
0271     mpc10->mpcc_in_use_mask |= 1 << mpcc_id;
0272 
0273     return new_mpcc;
0274 }
0275 
0276 /*
0277  * Remove a specified MPCC from the MPC tree.
0278  *
0279  * Parameters:
0280  * [in/out] mpc     - MPC context.
0281  * [in/out] tree    - MPC tree structure that plane will be removed from.
0282  * [in/out] mpcc    - MPCC to be removed from tree.
0283  *
0284  * Return:  void
0285  */
0286 void mpc1_remove_mpcc(
0287     struct mpc *mpc,
0288     struct mpc_tree *tree,
0289     struct mpcc *mpcc_to_remove)
0290 {
0291     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0292     bool found = false;
0293     int mpcc_id = mpcc_to_remove->mpcc_id;
0294 
0295     if (tree->opp_list == mpcc_to_remove) {
0296         found = true;
0297         /* remove MPCC from top of tree */
0298         if (mpcc_to_remove->mpcc_bot) {
0299             /* set the next MPCC in list to be the top MPCC */
0300             tree->opp_list = mpcc_to_remove->mpcc_bot;
0301             REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, tree->opp_list->mpcc_id);
0302         } else {
0303             /* there are no other MPCC is list */
0304             tree->opp_list = NULL;
0305             REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, 0xf);
0306         }
0307     } else {
0308         /* find mpcc to remove MPCC list */
0309         struct mpcc *temp_mpcc = tree->opp_list;
0310 
0311         while (temp_mpcc && temp_mpcc->mpcc_bot != mpcc_to_remove)
0312             temp_mpcc = temp_mpcc->mpcc_bot;
0313 
0314         if (temp_mpcc && temp_mpcc->mpcc_bot == mpcc_to_remove) {
0315             found = true;
0316             temp_mpcc->mpcc_bot = mpcc_to_remove->mpcc_bot;
0317             if (mpcc_to_remove->mpcc_bot) {
0318                 /* remove MPCC in middle of list */
0319                 REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0,
0320                         MPCC_BOT_SEL, mpcc_to_remove->mpcc_bot->mpcc_id);
0321             } else {
0322                 /* remove MPCC from bottom of list */
0323                 REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0,
0324                         MPCC_BOT_SEL, 0xf);
0325                 REG_UPDATE(MPCC_CONTROL[temp_mpcc->mpcc_id],
0326                         MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_PASSTHROUGH);
0327             }
0328         }
0329     }
0330 
0331     if (found) {
0332         /* turn off MPCC mux registers */
0333         REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
0334         REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
0335         REG_SET(MPCC_OPP_ID[mpcc_id],  0, MPCC_OPP_ID,  0xf);
0336         REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, 0xf);
0337 
0338         /* mark this mpcc as not in use */
0339         mpc10->mpcc_in_use_mask &= ~(1 << mpcc_id);
0340         mpcc_to_remove->dpp_id = 0xf;
0341         mpcc_to_remove->mpcc_bot = NULL;
0342     } else {
0343         /* In case of resume from S3/S4, remove mpcc from bios left over */
0344         REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
0345         REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
0346         REG_SET(MPCC_OPP_ID[mpcc_id],  0, MPCC_OPP_ID,  0xf);
0347         REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, 0xf);
0348     }
0349 }
0350 
0351 static void mpc1_init_mpcc(struct mpcc *mpcc, int mpcc_inst)
0352 {
0353     mpcc->mpcc_id = mpcc_inst;
0354     mpcc->dpp_id = 0xf;
0355     mpcc->mpcc_bot = NULL;
0356     mpcc->blnd_cfg.overlap_only = false;
0357     mpcc->blnd_cfg.global_alpha = 0xff;
0358     mpcc->blnd_cfg.global_gain = 0xff;
0359     mpcc->sm_cfg.enable = false;
0360 }
0361 
0362 /*
0363  * Reset the MPCC HW status by disconnecting all muxes.
0364  *
0365  * Parameters:
0366  * [in/out] mpc     - MPC context.
0367  *
0368  * Return:  void
0369  */
0370 void mpc1_mpc_init(struct mpc *mpc)
0371 {
0372     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0373     int mpcc_id;
0374     int opp_id;
0375 
0376     mpc10->mpcc_in_use_mask = 0;
0377     for (mpcc_id = 0; mpcc_id < mpc10->num_mpcc; mpcc_id++) {
0378         REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
0379         REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
0380         REG_SET(MPCC_OPP_ID[mpcc_id],  0, MPCC_OPP_ID,  0xf);
0381         REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, 0xf);
0382 
0383         mpc1_init_mpcc(&(mpc->mpcc_array[mpcc_id]), mpcc_id);
0384     }
0385 
0386     for (opp_id = 0; opp_id < MAX_OPP; opp_id++) {
0387         if (REG(MUX[opp_id]))
0388             REG_UPDATE(MUX[opp_id], MPC_OUT_MUX, 0xf);
0389     }
0390 }
0391 
0392 void mpc1_mpc_init_single_inst(struct mpc *mpc, unsigned int mpcc_id)
0393 {
0394     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0395     int opp_id;
0396 
0397     REG_GET(MPCC_OPP_ID[mpcc_id], MPCC_OPP_ID, &opp_id);
0398 
0399     REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
0400     REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
0401     REG_SET(MPCC_OPP_ID[mpcc_id],  0, MPCC_OPP_ID,  0xf);
0402     REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, 0xf);
0403 
0404     mpc1_init_mpcc(&(mpc->mpcc_array[mpcc_id]), mpcc_id);
0405 
0406     if (opp_id < MAX_OPP && REG(MUX[opp_id]))
0407         REG_UPDATE(MUX[opp_id], MPC_OUT_MUX, 0xf);
0408 }
0409 
0410 
0411 void mpc1_init_mpcc_list_from_hw(
0412     struct mpc *mpc,
0413     struct mpc_tree *tree)
0414 {
0415     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0416     unsigned int opp_id;
0417     unsigned int top_sel;
0418     unsigned int bot_sel;
0419     unsigned int out_mux;
0420     struct mpcc *mpcc;
0421     int mpcc_id;
0422     int bot_mpcc_id;
0423 
0424     REG_GET(MUX[tree->opp_id], MPC_OUT_MUX, &out_mux);
0425 
0426     if (out_mux != 0xf) {
0427         for (mpcc_id = 0; mpcc_id < mpc10->num_mpcc; mpcc_id++) {
0428             REG_GET(MPCC_OPP_ID[mpcc_id],  MPCC_OPP_ID,  &opp_id);
0429             REG_GET(MPCC_TOP_SEL[mpcc_id], MPCC_TOP_SEL, &top_sel);
0430             REG_GET(MPCC_BOT_SEL[mpcc_id],  MPCC_BOT_SEL, &bot_sel);
0431 
0432             if (bot_sel == mpcc_id)
0433                 bot_sel = 0xf;
0434 
0435             if ((opp_id == tree->opp_id) && (top_sel != 0xf)) {
0436                 mpcc = mpc1_get_mpcc(mpc, mpcc_id);
0437                 mpcc->dpp_id = top_sel;
0438                 mpc10->mpcc_in_use_mask |= 1 << mpcc_id;
0439 
0440                 if (out_mux == mpcc_id)
0441                     tree->opp_list = mpcc;
0442                 if (bot_sel != 0xf && bot_sel < mpc10->num_mpcc) {
0443                     bot_mpcc_id = bot_sel;
0444                     REG_GET(MPCC_OPP_ID[bot_mpcc_id],  MPCC_OPP_ID,  &opp_id);
0445                     REG_GET(MPCC_TOP_SEL[bot_mpcc_id], MPCC_TOP_SEL, &top_sel);
0446                     if ((opp_id == tree->opp_id) && (top_sel != 0xf)) {
0447                         struct mpcc *mpcc_bottom = mpc1_get_mpcc(mpc, bot_mpcc_id);
0448 
0449                         mpcc->mpcc_bot = mpcc_bottom;
0450                     }
0451                 }
0452             }
0453         }
0454     }
0455 }
0456 
0457 void mpc1_read_mpcc_state(
0458         struct mpc *mpc,
0459         int mpcc_inst,
0460         struct mpcc_state *s)
0461 {
0462     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0463 
0464     REG_GET(MPCC_OPP_ID[mpcc_inst], MPCC_OPP_ID, &s->opp_id);
0465     REG_GET(MPCC_TOP_SEL[mpcc_inst], MPCC_TOP_SEL, &s->dpp_id);
0466     REG_GET(MPCC_BOT_SEL[mpcc_inst], MPCC_BOT_SEL, &s->bot_mpcc_id);
0467     REG_GET_4(MPCC_CONTROL[mpcc_inst], MPCC_MODE, &s->mode,
0468             MPCC_ALPHA_BLND_MODE, &s->alpha_mode,
0469             MPCC_ALPHA_MULTIPLIED_MODE, &s->pre_multiplied_alpha,
0470             MPCC_BLND_ACTIVE_OVERLAP_ONLY, &s->overlap_only);
0471     REG_GET_2(MPCC_STATUS[mpcc_inst], MPCC_IDLE, &s->idle,
0472             MPCC_BUSY, &s->busy);
0473 }
0474 
0475 void mpc1_cursor_lock(struct mpc *mpc, int opp_id, bool lock)
0476 {
0477     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0478 
0479     REG_SET(CUR[opp_id], 0, CUR_VUPDATE_LOCK_SET, lock ? 1 : 0);
0480 }
0481 
0482 unsigned int mpc1_get_mpc_out_mux(struct mpc *mpc, int opp_id)
0483 {
0484     struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
0485     uint32_t val = 0xf;
0486 
0487     if (opp_id < MAX_OPP && REG(MUX[opp_id]))
0488         REG_GET(MUX[opp_id], MPC_OUT_MUX, &val);
0489 
0490     return val;
0491 }
0492 
0493 static const struct mpc_funcs dcn10_mpc_funcs = {
0494     .read_mpcc_state = mpc1_read_mpcc_state,
0495     .insert_plane = mpc1_insert_plane,
0496     .remove_mpcc = mpc1_remove_mpcc,
0497     .mpc_init = mpc1_mpc_init,
0498     .mpc_init_single_inst = mpc1_mpc_init_single_inst,
0499     .get_mpcc_for_dpp = mpc1_get_mpcc_for_dpp,
0500     .wait_for_idle = mpc1_assert_idle_mpcc,
0501     .assert_mpcc_idle_before_connect = mpc1_assert_mpcc_idle_before_connect,
0502     .init_mpcc_list_from_hw = mpc1_init_mpcc_list_from_hw,
0503     .update_blending = mpc1_update_blending,
0504     .cursor_lock = mpc1_cursor_lock,
0505     .set_denorm = NULL,
0506     .set_denorm_clamp = NULL,
0507     .set_output_csc = NULL,
0508     .set_output_gamma = NULL,
0509     .get_mpc_out_mux = mpc1_get_mpc_out_mux,
0510     .set_bg_color = mpc1_set_bg_color,
0511 };
0512 
0513 void dcn10_mpc_construct(struct dcn10_mpc *mpc10,
0514     struct dc_context *ctx,
0515     const struct dcn_mpc_registers *mpc_regs,
0516     const struct dcn_mpc_shift *mpc_shift,
0517     const struct dcn_mpc_mask *mpc_mask,
0518     int num_mpcc)
0519 {
0520     int i;
0521 
0522     mpc10->base.ctx = ctx;
0523 
0524     mpc10->base.funcs = &dcn10_mpc_funcs;
0525 
0526     mpc10->mpc_regs = mpc_regs;
0527     mpc10->mpc_shift = mpc_shift;
0528     mpc10->mpc_mask = mpc_mask;
0529 
0530     mpc10->mpcc_in_use_mask = 0;
0531     mpc10->num_mpcc = num_mpcc;
0532 
0533     for (i = 0; i < MAX_MPCC; i++)
0534         mpc1_init_mpcc(&mpc10->base.mpcc_array[i], i);
0535 }
0536