1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2025 Advanced Micro Devices, Inc. 4 #include "reg_helper.h" 5 #include "dc.h" 6 #include "dcn60_mpc.h" 7 #include "dcn10/dcn10_cm_common.h" 8 #include "basics/conversion.h" 9 #include "mpc.h" 10 11 #define REG(reg)\ 12 mpc60->mpc_regs->reg 13 14 #define CTX \ 15 mpc60->base.ctx 16 17 #undef FN 18 #define FN(reg_name, field_name) \ 19 mpc60->mpc_shift->field_name, mpc60->mpc_mask->field_name 20 21 /* 22 * Insert DPP into MPC tree based on specified blending position. 23 * Only used for planes that are part of blending chain for OPP output 24 * 25 * Parameters: 26 * [in/out] mpc - MPC context. 27 * [in/out] tree - MPC tree structure that plane will be added to. 28 * [in] blnd_cfg - MPCC blending configuration for the new blending layer. 29 * [in] sm_cfg - MPCC stereo mix configuration for the new blending layer. 30 * stereo mix must disable for the very bottom layer of the tree config. 31 * [in] insert_above_mpcc - Insert new plane above this MPCC. If NULL, insert as bottom plane. 32 * [in] dpp_id - DPP instance for the plane to be added. 33 * [in] mpcc_id - The MPCC physical instance to use for blending. 34 * 35 * Return: struct mpcc* - MPCC that was added. 36 */ 37 static struct mpcc *mpc60_insert_plane( 38 struct mpc *mpc, 39 struct mpc_tree *tree, 40 struct mpcc_blnd_cfg *blnd_cfg, 41 struct mpcc_sm_cfg *sm_cfg, 42 struct mpcc *insert_above_mpcc, 43 int dpp_id, 44 int mpcc_id) 45 { 46 (void)sm_cfg; 47 struct dcn60_mpc *mpc60 = TO_DCN60_MPC(mpc); 48 struct mpcc *new_mpcc = NULL; 49 50 /* sanity check parameters */ 51 ASSERT(mpcc_id < mpc60->num_mpcc); 52 ASSERT(!(mpc60->mpcc_in_use_mask & 1 << mpcc_id)); 53 54 if (insert_above_mpcc) { 55 /* check insert_above_mpcc exist in tree->opp_list */ 56 struct mpcc *temp_mpcc = tree->opp_list; 57 58 if (temp_mpcc != insert_above_mpcc) 59 while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc) 60 temp_mpcc = temp_mpcc->mpcc_bot; 61 if (temp_mpcc == NULL) 62 return NULL; 63 } 64 65 /* Get and update MPCC struct parameters */ 66 new_mpcc = mpc1_get_mpcc(mpc, mpcc_id); 67 new_mpcc->dpp_id = dpp_id; 68 69 /* program mux and MPCC_MODE */ 70 if (insert_above_mpcc) { 71 new_mpcc->mpcc_bot = insert_above_mpcc; 72 REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, insert_above_mpcc->mpcc_id); 73 REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING); 74 } else { 75 new_mpcc->mpcc_bot = NULL; 76 REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf); 77 REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_ONLY); 78 } 79 REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, dpp_id); 80 REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, tree->opp_id); 81 82 /* Configure VUPDATE lock set for this MPCC to map to the OPP */ 83 REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, tree->opp_id); 84 85 /* update mpc tree mux setting */ 86 if (tree->opp_list == insert_above_mpcc) { 87 /* insert the toppest mpcc */ 88 tree->opp_list = new_mpcc; 89 REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, mpcc_id); 90 } else { 91 /* find insert position */ 92 struct mpcc *temp_mpcc = tree->opp_list; 93 94 while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc) 95 temp_mpcc = temp_mpcc->mpcc_bot; 96 if (temp_mpcc && temp_mpcc->mpcc_bot == insert_above_mpcc) { 97 REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0, MPCC_BOT_SEL, mpcc_id); 98 temp_mpcc->mpcc_bot = new_mpcc; 99 if (!insert_above_mpcc) 100 REG_UPDATE(MPCC_CONTROL[temp_mpcc->mpcc_id], 101 MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING); 102 } 103 } 104 105 /* update the blending configuration */ 106 mpc->funcs->update_blending(mpc, blnd_cfg, mpcc_id); 107 108 /* mark this mpcc as in use */ 109 mpc60->mpcc_in_use_mask |= 1 << mpcc_id; 110 111 return new_mpcc; 112 } 113 114 void mpc60_program_rmcm_lut_read_write_control(struct mpc *mpc, const enum MCM_LUT_ID id, 115 bool lut_bank_a, bool enabled, int mpcc_id) 116 { 117 struct dcn60_mpc *mpc60 = TO_DCN60_MPC(mpc); 118 119 switch (id) { 120 case MCM_LUT_3DLUT: 121 REG_UPDATE(MPC_RMCM_3DLUT_MODE[mpcc_id], MPC_RMCM_3DLUT_MODE, 122 (!enabled) ? 0 : 123 (lut_bank_a) ? 1 : 2); 124 break; 125 126 case MCM_LUT_SHAPER: 127 REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id], 128 MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7); 129 130 REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id], 131 MPC_RMCM_SHAPER_LUT_WRITE_SEL, 132 lut_bank_a == true ? 0 : 1); 133 134 REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[mpcc_id], 0, 135 MPC_RMCM_SHAPER_LUT_INDEX, 0); 136 break; 137 default: 138 break; 139 } 140 } 141 142 static void mpc60_program_lut_read_write_control(struct mpc *mpc, 143 const enum MCM_LUT_ID id, 144 const bool lut_bank_a, 145 const unsigned int bit_depth, 146 const int mpcc_id) 147 { 148 struct dcn60_mpc *mpc60 = TO_DCN60_MPC(mpc); 149 150 switch (id) { 151 case MCM_LUT_3DLUT: 152 mpc32_select_3dlut_ram_mask(mpc, 0xf, mpcc_id); 153 REG_UPDATE(MPCC_MCM_3DLUT_READ_WRITE_CONTROL[mpcc_id], 154 MPCC_MCM_3DLUT_30BIT_EN, (bit_depth == 10) ? 1 : 0); 155 break; 156 case MCM_LUT_SHAPER: 157 mpc32_configure_shaper_lut(mpc, lut_bank_a, mpcc_id); 158 break; 159 case MCM_LUT_1DLUT: 160 mpc32_configure_post1dlut(mpc, lut_bank_a, mpcc_id); 161 break; 162 } 163 } 164 165 static uint32_t mpc60_cm_lut_size_to_3dlut_size(const enum dc_cm_lut_size cm_size) 166 { 167 uint32_t size = 0; 168 169 switch (cm_size) { 170 case CM_LUT_SIZE_999: 171 size = 1; 172 break; 173 case CM_LUT_SIZE_171717: 174 size = 0; 175 break; 176 default: 177 /* invalid LUT size for MCM */ 178 ASSERT(false); 179 size = 0; 180 break; 181 } 182 183 return size; 184 } 185 186 static void mpc60_program_lut_mode( 187 struct mpc *mpc, 188 const enum MCM_LUT_ID id, 189 const bool enable, 190 const bool lut_bank_a, 191 const enum dc_cm_lut_size size, 192 const int mpcc_id) 193 { 194 uint32_t lut_size; 195 struct dcn60_mpc *mpc60 = TO_DCN60_MPC(mpc); 196 197 switch (id) { 198 case MCM_LUT_3DLUT: 199 if (enable) { 200 lut_size = mpc60_cm_lut_size_to_3dlut_size(size); 201 REG_UPDATE_2(MPCC_MCM_3DLUT_MODE[mpcc_id], 202 MPCC_MCM_3DLUT_MODE, 1, 203 MPCC_MCM_3DLUT_SIZE, lut_size); 204 } else { 205 if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc) 206 mpc32_power_on_shaper_3dlut(mpc, mpcc_id, false); 207 REG_UPDATE(MPCC_MCM_3DLUT_MODE[mpcc_id], MPCC_MCM_3DLUT_MODE, 0); 208 } 209 break; 210 case MCM_LUT_SHAPER: 211 if (enable) { 212 REG_UPDATE(MPCC_MCM_SHAPER_CONTROL[mpcc_id], MPCC_MCM_SHAPER_LUT_MODE, lut_bank_a ? 1 : 2); 213 } else { 214 if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc) 215 mpc32_power_on_shaper_3dlut(mpc, mpcc_id, false); 216 REG_UPDATE(MPCC_MCM_SHAPER_CONTROL[mpcc_id], MPCC_MCM_SHAPER_LUT_MODE, 0); 217 } 218 break; 219 case MCM_LUT_1DLUT: 220 if (enable) { 221 REG_UPDATE(MPCC_MCM_1DLUT_CONTROL[mpcc_id], 222 MPCC_MCM_1DLUT_MODE, 2); 223 } else { 224 if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc) 225 mpc32_power_on_blnd_lut(mpc, mpcc_id, false); 226 REG_UPDATE(MPCC_MCM_1DLUT_CONTROL[mpcc_id], 227 MPCC_MCM_1DLUT_MODE, 0); 228 } 229 REG_UPDATE(MPCC_MCM_1DLUT_CONTROL[mpcc_id], 230 MPCC_MCM_1DLUT_SELECT, lut_bank_a ? 0 : 1); 231 break; 232 } 233 } 234 235 static bool mpc60_program_3dlut( 236 struct mpc *mpc, 237 const struct tetrahedral_params *params, 238 int mpcc_id) 239 { 240 union mcm_lut_params lut_params = { 0 }; 241 lut_params.lut3d = params; 242 243 mpc60_program_lut_read_write_control(mpc, 244 MCM_LUT_3DLUT, 245 true, 246 params->use_12bits ? 12 : 10, 247 mpcc_id); 248 mpc401_populate_lut(mpc, MCM_LUT_3DLUT, &lut_params, true, mpcc_id); 249 mpc60_program_lut_mode(mpc, 250 MCM_LUT_3DLUT, 251 true, 252 true, 253 params->use_tetrahedral_9 ? CM_LUT_SIZE_999 : CM_LUT_SIZE_171717, 254 mpcc_id); 255 256 return true; 257 } 258 259 static const struct mpc_funcs dcn60_mpc_funcs = { 260 .read_mpcc_state = mpc1_read_mpcc_state, 261 .insert_plane = mpc60_insert_plane, 262 .remove_mpcc = mpc1_remove_mpcc, 263 .mpc_init = mpc32_mpc_init, 264 .mpc_init_single_inst = mpc3_mpc_init_single_inst, 265 .update_blending = mpc42_update_blending, 266 .cursor_lock = mpc1_cursor_lock, 267 .get_mpcc_for_dpp = mpc1_get_mpcc_for_dpp, 268 .wait_for_idle = mpc2_assert_idle_mpcc, 269 .assert_mpcc_idle_before_connect = mpc2_assert_mpcc_idle_before_connect, 270 .init_mpcc_list_from_hw = mpc1_init_mpcc_list_from_hw, 271 .set_denorm = mpc3_set_denorm, 272 .set_denorm_clamp = mpc3_set_denorm_clamp, 273 .set_output_csc = mpc3_set_output_csc, 274 .set_ocsc_default = mpc3_set_ocsc_default, 275 .set_output_gamma = mpc3_set_output_gamma, 276 .set_gamut_remap = mpc401_set_gamut_remap, 277 .program_shaper = mpc32_program_shaper, 278 .program_3dlut = mpc60_program_3dlut, 279 .program_1dlut = mpc32_program_post1dlut, 280 .power_on_mpc_mem_pwr = mpc3_power_on_ogam_lut, 281 .get_mpc_out_mux = mpc1_get_mpc_out_mux, 282 .mpc_read_reg_state = mpc3_read_reg_state, 283 .set_bg_color = mpc1_set_bg_color, 284 .set_movable_cm_location = mpc401_set_movable_cm_location, 285 .update_3dlut_fast_load_select = mpc401_update_3dlut_fast_load_select, 286 .get_3dlut_fast_load_status = mpc401_get_3dlut_fast_load_status, 287 .populate_lut = mpc401_populate_lut, 288 .program_lut_read_write_control = mpc60_program_lut_read_write_control, 289 .program_lut_mode = mpc60_program_lut_mode, 290 .get_lut_mode = mpc401_get_lut_mode, 291 .rmcm = { 292 .enable_3dlut_fl = mpc42_enable_3dlut_fl, 293 .update_3dlut_fast_load_select = mpc42_update_3dlut_fast_load_select, 294 .program_lut_read_write_control = mpc60_program_rmcm_lut_read_write_control, 295 .program_lut_mode = mpc42_program_lut_mode, 296 .program_3dlut_size = mpc42_program_rmcm_3dlut_size, 297 .program_bias_scale = mpc42_program_rmcm_3dlut_fast_load_bias_scale, 298 .program_bit_depth = mpc42_program_rmcm_bit_depth, 299 .power_on_shaper_3dlut = mpc42_power_on_rmcm_shaper_3dlut, 300 .populate_lut = mpc42_populate_rmcm_lut, 301 .get_3dlut_mode = mpc42_get_rmcm_3dlut_mode, 302 }, 303 }; 304 305 void dcn60_mpc_construct(struct dcn60_mpc *mpc60, 306 struct dc_context *ctx, 307 const struct dcn60_mpc_registers *mpc_regs, 308 const struct dcn60_mpc_shift *mpc_shift, 309 const struct dcn60_mpc_mask *mpc_mask, 310 int num_mpcc, 311 int num_rmu) 312 { 313 int i; 314 315 mpc60->base.ctx = ctx; 316 317 mpc60->base.funcs = &dcn60_mpc_funcs; 318 319 mpc60->mpc_regs = mpc_regs; 320 mpc60->mpc_shift = mpc_shift; 321 mpc60->mpc_mask = mpc_mask; 322 323 mpc60->mpcc_in_use_mask = 0; 324 mpc60->num_mpcc = num_mpcc; 325 mpc60->num_rmu = num_rmu; 326 327 for (i = 0; i < MAX_MPCC; i++) 328 mpc42_init_mpcc(&mpc60->base.mpcc_array[i], i); 329 } 330 331