0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
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
0051 while (bottommost_mpcc->mpcc_bot) {
0052
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
0061
0062
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
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
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
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
0208 ASSERT(mpcc_id < mpc10->num_mpcc);
0209 ASSERT(!(mpc10->mpcc_in_use_mask & 1 << mpcc_id));
0210
0211 if (insert_above_mpcc) {
0212
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
0222 new_mpcc = mpc1_get_mpcc(mpc, mpcc_id);
0223 new_mpcc->dpp_id = dpp_id;
0224
0225
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
0239 REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, tree->opp_id);
0240
0241
0242 if (tree->opp_list == insert_above_mpcc) {
0243
0244 tree->opp_list = new_mpcc;
0245 REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, mpcc_id);
0246 } else {
0247
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
0262 mpc->funcs->update_blending(mpc, blnd_cfg, mpcc_id);
0263
0264
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
0271 mpc10->mpcc_in_use_mask |= 1 << mpcc_id;
0272
0273 return new_mpcc;
0274 }
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
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
0298 if (mpcc_to_remove->mpcc_bot) {
0299
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
0304 tree->opp_list = NULL;
0305 REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, 0xf);
0306 }
0307 } else {
0308
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
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
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
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
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
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
0364
0365
0366
0367
0368
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