#include "dm_services.h"
#include "dm_helpers.h"
#include "core_types.h"
#include "resource.h"
#include "dccg.h"
#include "dce/dce_hwseq.h"
#include "dcn30/dcn30_cm_common.h"
#include "reg_helper.h"
#include "abm.h"
#include "hubp.h"
#include "dchubbub.h"
#include "timing_generator.h"
#include "opp.h"
#include "ipp.h"
#include "mpc.h"
#include "mcif_wb.h"
#include "dc_dmub_srv.h"
#include "link_hwss.h"
#include "dpcd_defs.h"
#include "dcn401/dcn401_hwseq.h"
#include "dcn42_hwseq.h"
#include "clk_mgr.h"
#include "dsc.h"
#include "dcn20/dcn20_optc.h"
#include "dce/dmub_hw_lock_mgr.h"
#include "dcn42/dcn42_resource.h"
#include "link_service.h"
#include "../dcn10/dcn10_hwseq.h"
#include "../dcn20/dcn20_hwseq.h"
#include "dc_state_priv.h"
#include "dc_stream_priv.h"
#include "dcn35/dcn35_hwseq.h"
#include "dcn42/dcn42_hwseq.h"
#include "dio/dcn10/dcn10_dio.h"
#define DC_LOGGER \
ctx->logger
#define CTX \
hws->ctx
#define REG(reg)\
hws->regs->reg
#undef FN
#define FN(reg_name, field_name) \
hws->shifts->field_name, hws->masks->field_name
static void print_pg_status(struct dc *dc, const char *debug_func, const char *debug_log)
{
if (dc->debug.enable_pg_cntl_debug_logs && dc->res_pool->pg_cntl) {
if (dc->res_pool->pg_cntl->funcs->print_pg_status)
dc->res_pool->pg_cntl->funcs->print_pg_status(dc->res_pool->pg_cntl, debug_func, debug_log);
}
}
void dcn42_init_hw(struct dc *dc)
{
struct abm **abms = dc->res_pool->multiple_abms;
struct dce_hwseq *hws = dc->hwseq;
struct dc_bios *dcb = dc->ctx->dc_bios;
struct resource_pool *res_pool = dc->res_pool;
unsigned int i;
unsigned int edp_num;
uint32_t backlight = MAX_BACKLIGHT_LEVEL;
uint32_t user_level = MAX_BACKLIGHT_LEVEL;
bool dchub_ref_freq_changed;
int current_dchub_ref_freq = 0;
if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) {
dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
dc->caps.dcmode_power_limits_present = dc->clk_mgr->funcs->is_dc_mode_present &&
dc->clk_mgr->funcs->is_dc_mode_present(dc->clk_mgr);
}
if (res_pool->dccg->funcs->dccg_init)
res_pool->dccg->funcs->dccg_init(res_pool->dccg);
if (dc->debug.enable_mem_low_power.bits.optc) {
REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
}
if (dc->debug.enable_mem_low_power.bits.vga) {
REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
}
if (dc->ctx->dc_bios->fw_info_valid) {
res_pool->ref_clocks.xtalin_clock_inKhz =
dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
if (res_pool->hubbub) {
(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
&res_pool->ref_clocks.dccg_ref_clock_inKhz);
current_dchub_ref_freq = res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
res_pool->ref_clocks.dccg_ref_clock_inKhz,
&res_pool->ref_clocks.dchub_ref_clock_inKhz);
} else {
res_pool->ref_clocks.dccg_ref_clock_inKhz =
res_pool->ref_clocks.xtalin_clock_inKhz;
res_pool->ref_clocks.dchub_ref_clock_inKhz =
res_pool->ref_clocks.xtalin_clock_inKhz;
}
} else
ASSERT_CRITICAL(false);
for (i = 0; i < dc->link_count; i++) {
struct dc_link *link = dc->links[i];
if (link->ep_type != DISPLAY_ENDPOINT_PHY)
continue;
link->link_enc->funcs->hw_init(link->link_enc);
if (link->link_enc->funcs->is_dig_enabled &&
link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
link->link_status.link_active = true;
link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
if (link->link_enc->funcs->fec_is_active &&
link->link_enc->funcs->fec_is_active(link->link_enc))
link->fec_state = dc_link_fec_enabled;
}
}
if (hws->funcs.enable_power_gating_plane)
hws->funcs.enable_power_gating_plane(dc->hwseq, true);
dc->link_srv->blank_all_dp_displays(dc);
if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
if (dc->hwss.enable_accelerated_mode && dc->debug.disable_boot_optimizations)
dc->hwss.enable_accelerated_mode(dc, dc->current_state);
else
hws->funcs.init_pipes(dc, dc->current_state);
if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
}
if (!dc->config.seamless_boot_edp_requested) {
struct dc_link *edp_links[MAX_NUM_EDP];
struct dc_link *edp_link;
dc_get_edp_links(dc, edp_links, &edp_num);
if (edp_num) {
for (i = 0; i < edp_num; i++) {
edp_link = edp_links[i];
if (edp_link->link_enc->funcs->is_dig_enabled &&
edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
dc->hwss.edp_backlight_control &&
hws->funcs.power_down &&
dc->hwss.edp_power_control) {
dc->hwss.edp_backlight_control(edp_link, false);
hws->funcs.power_down(dc);
dc->hwss.edp_power_control(edp_link, false);
}
}
} else {
for (i = 0; i < dc->link_count; i++) {
struct dc_link *link = dc->links[i];
if (link && link->link_enc &&
link->link_enc->funcs->is_dig_enabled &&
link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
hws->funcs.power_down) {
hws->funcs.power_down(dc);
break;
}
}
}
}
for (i = 0; i < res_pool->audio_count; i++) {
struct audio *audio = res_pool->audios[i];
audio->funcs->hw_init(audio);
}
for (i = 0; i < dc->link_count; i++) {
struct dc_link *link = dc->links[i];
if (link->panel_cntl) {
backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL;
}
}
for (i = 0; i < dc->res_pool->pipe_count; i++) {
if (abms[i] != NULL && abms[i]->funcs != NULL)
abms[i]->funcs->abm_init(abms[i], backlight, user_level);
}
if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl)
dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false);
if (!dc->debug.disable_clock_gate) {
REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0);
REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
}
dcn401_setup_hpo_hw_control(hws, true);
if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges)
dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
dc->res_pool->hubbub->funcs->force_pstate_change_control(
dc->res_pool->hubbub, false, false);
if (dc->res_pool->hubbub->funcs->init_crb)
dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
if (dc->res_pool->hubbub->funcs->set_request_limit &&
dc->clk_mgr && dc->clk_mgr->bw_params &&
dc->config.sdpif_request_limit_words_per_umc > 0)
dc->res_pool->hubbub->funcs->set_request_limit(dc->res_pool->hubbub,
dc->clk_mgr->bw_params->num_channels,
dc->config.sdpif_request_limit_words_per_umc);
if (dc->ctx->dmub_srv) {
dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv);
dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver > 0;
dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;
dc->debug.fams2_config.bits.enable &=
dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver;
dchub_ref_freq_changed =
res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq;
if ((!dc->debug.fams2_config.bits.enable || dchub_ref_freq_changed) &&
dc->res_pool->funcs->update_bw_bounding_box &&
dc->clk_mgr && dc->clk_mgr->bw_params) {
dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params);
}
}
if (dc->res_pool->pg_cntl) {
if (dc->res_pool->pg_cntl->funcs->init_pg_status)
dc->res_pool->pg_cntl->funcs->init_pg_status(dc->res_pool->pg_cntl);
}
print_pg_status(dc, __func__, ": after init_pg_status");
}
void dcn42_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
{
struct hubp *hubp = pipe_ctx->plane_res.hubp;
struct mpcc_blnd_cfg blnd_cfg = {0};
bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha;
int mpcc_id;
struct mpcc *new_mpcc;
struct mpc *mpc = dc->res_pool->mpc;
struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
blnd_cfg.overlap_only = false;
blnd_cfg.global_gain = 0xfff;
if (per_pixel_alpha) {
blnd_cfg.pre_multiplied_alpha = pipe_ctx->plane_state->pre_multiplied_alpha;
if (pipe_ctx->plane_state->global_alpha) {
blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
} else {
blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
}
} else {
blnd_cfg.pre_multiplied_alpha = false;
blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
}
if (pipe_ctx->plane_state->global_alpha)
blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
else
blnd_cfg.global_alpha = 0xfff;
blnd_cfg.background_color_bpc = 4;
blnd_cfg.bottom_gain_mode = 0;
blnd_cfg.top_gain = 0x1f000;
blnd_cfg.bottom_inside_gain = 0x1f000;
blnd_cfg.bottom_outside_gain = 0x1f000;
if (pipe_ctx->plane_state->format
== SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA)
blnd_cfg.pre_multiplied_alpha = false;
mpcc_id = hubp->inst;
if (!pipe_ctx->plane_state->update_flags.bits.full_update &&
!pipe_ctx->update_flags.bits.mpcc) {
mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id);
dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
return;
}
new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id);
if (new_mpcc != NULL)
mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc);
else
if (dc->debug.sanity_checks)
mpc->funcs->assert_mpcc_idle_before_connect(
dc->res_pool->mpc, mpcc_id);
new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc,
mpc_tree_params,
&blnd_cfg,
NULL,
NULL,
hubp->inst,
mpcc_id);
dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id);
ASSERT(new_mpcc != NULL);
hubp->opp_id = pipe_ctx->stream_res.opp->inst;
hubp->mpcc_id = mpcc_id;
}
void dcn42_program_cm_hist(
struct dc *dc,
struct pipe_ctx *pipe_ctx,
const struct dc_plane_state *plane_state)
{
(void)dc;
struct dpp *dpp = pipe_ctx->plane_res.dpp;
if (dpp && dpp->funcs->dpp_cm_hist_control)
dpp->funcs->dpp_cm_hist_control(dpp,
plane_state->cm_hist_control, plane_state->color_space);
}
static void dc_get_lut_xbar(
enum dc_cm2_gpu_mem_pixel_component_order order,
enum hubp_3dlut_fl_crossbar_bit_slice *cr_r,
enum hubp_3dlut_fl_crossbar_bit_slice *y_g,
enum hubp_3dlut_fl_crossbar_bit_slice *cb_b)
{
switch (order) {
case DC_CM2_GPU_MEM_PIXEL_COMPONENT_ORDER_RGBA:
*cr_r = hubp_3dlut_fl_crossbar_bit_slice_32_47;
*y_g = hubp_3dlut_fl_crossbar_bit_slice_16_31;
*cb_b = hubp_3dlut_fl_crossbar_bit_slice_0_15;
break;
case DC_CM2_GPU_MEM_PIXEL_COMPONENT_ORDER_BGRA:
*cr_r = hubp_3dlut_fl_crossbar_bit_slice_0_15;
*y_g = hubp_3dlut_fl_crossbar_bit_slice_16_31;
*cb_b = hubp_3dlut_fl_crossbar_bit_slice_32_47;
break;
}
}
static void dc_get_lut_mode(
enum dc_cm2_gpu_mem_layout layout,
enum hubp_3dlut_fl_mode *mode,
enum hubp_3dlut_fl_addressing_mode *addr_mode)
{
switch (layout) {
case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_RGB:
*mode = hubp_3dlut_fl_mode_native_1;
*addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
break;
case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_BGR:
*mode = hubp_3dlut_fl_mode_native_2;
*addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
break;
case DC_CM2_GPU_MEM_LAYOUT_1D_PACKED_LINEAR:
*mode = hubp_3dlut_fl_mode_transform;
*addr_mode = hubp_3dlut_fl_addressing_mode_simple_linear;
break;
default:
*mode = hubp_3dlut_fl_mode_disable;
*addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
break;
}
}
static void dc_get_lut_format(
enum dc_cm2_gpu_mem_format dc_format,
enum hubp_3dlut_fl_format *format)
{
switch (dc_format) {
case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12MSB:
*format = hubp_3dlut_fl_format_unorm_12msb_bitslice;
break;
case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12LSB:
*format = hubp_3dlut_fl_format_unorm_12lsb_bitslice;
break;
case DC_CM2_GPU_MEM_FORMAT_16161616_FLOAT_FP1_5_10:
*format = hubp_3dlut_fl_format_float_fp1_5_10;
break;
}
}
static bool dc_is_rmcm_3dlut_supported(struct hubp *hubp, struct mpc *mpc)
{
if (mpc->funcs->rmcm.power_on_shaper_3dlut &&
mpc->funcs->rmcm.fl_3dlut_configure &&
hubp->funcs->hubp_program_3dlut_fl_config)
return true;
return false;
}
static bool is_rmcm_3dlut_fl_supported(struct dc *dc, enum dc_cm2_gpu_mem_size size)
{
if (!dc->caps.color.mpc.rmcm_3d_lut_caps.dma_3d_lut)
return false;
if (size == DC_CM2_GPU_MEM_SIZE_171717)
return dc->caps.color.mpc.rmcm_3d_lut_caps.lut_dim_caps.dim_17 != 0u;
else if (size == DC_CM2_GPU_MEM_SIZE_333333)
return dc->caps.color.mpc.rmcm_3d_lut_caps.lut_dim_caps.dim_33 != 0u;
return false;
}
static void dcn42_set_mcm_location_post_blend(struct dc *dc, struct pipe_ctx *pipe_ctx, bool bPostBlend)
{
struct mpc *mpc = dc->res_pool->mpc;
int mpcc_id = pipe_ctx->plane_res.hubp->inst;
if (!pipe_ctx->plane_state)
return;
mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id);
pipe_ctx->plane_state->mcm_location = (bPostBlend) ?
MPCC_MOVABLE_CM_LOCATION_AFTER :
MPCC_MOVABLE_CM_LOCATION_BEFORE;
}
static void dcn42_get_mcm_lut_xable_from_pipe_ctx(struct dc *dc, struct pipe_ctx *pipe_ctx,
enum MCM_LUT_XABLE *shaper_xable,
enum MCM_LUT_XABLE *lut3d_xable,
enum MCM_LUT_XABLE *lut1d_xable)
{
enum dc_cm2_shaper_3dlut_setting shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL;
bool lut1d_enable = false;
struct mpc *mpc = dc->res_pool->mpc;
int mpcc_id = pipe_ctx->plane_res.hubp->inst;
if (!pipe_ctx->plane_state)
return;
shaper_3dlut_setting = pipe_ctx->plane_state->mcm_shaper_3dlut_setting;
lut1d_enable = pipe_ctx->plane_state->mcm_lut1d_enable;
mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id);
pipe_ctx->plane_state->mcm_location = MPCC_MOVABLE_CM_LOCATION_BEFORE;
*lut1d_xable = lut1d_enable ? MCM_LUT_ENABLE : MCM_LUT_DISABLE;
switch (shaper_3dlut_setting) {
case DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL:
*lut3d_xable = *shaper_xable = MCM_LUT_DISABLE;
break;
case DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER:
*lut3d_xable = MCM_LUT_DISABLE;
*shaper_xable = MCM_LUT_ENABLE;
break;
case DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT:
*lut3d_xable = *shaper_xable = MCM_LUT_ENABLE;
break;
}
}
static void fl_get_lut_mode(
enum dc_cm2_gpu_mem_layout layout,
enum dc_cm2_gpu_mem_size size,
enum hubp_3dlut_fl_mode *mode,
enum hubp_3dlut_fl_addressing_mode *addr_mode,
enum hubp_3dlut_fl_width *width)
{
*width = hubp_3dlut_fl_width_17;
if (size == DC_CM2_GPU_MEM_SIZE_333333)
*width = hubp_3dlut_fl_width_33;
switch (layout) {
case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_RGB:
*mode = hubp_3dlut_fl_mode_native_1;
*addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
break;
case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_BGR:
*mode = hubp_3dlut_fl_mode_native_2;
*addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
break;
case DC_CM2_GPU_MEM_LAYOUT_1D_PACKED_LINEAR:
*mode = hubp_3dlut_fl_mode_transform;
*addr_mode = hubp_3dlut_fl_addressing_mode_simple_linear;
break;
default:
*mode = hubp_3dlut_fl_mode_disable;
*addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear;
break;
}
}
bool dcn42_program_rmcm_luts(
struct hubp *hubp,
struct pipe_ctx *pipe_ctx,
enum dc_cm2_transfer_func_source lut3d_src,
struct dc_cm2_func_luts *mcm_luts,
struct mpc *mpc,
bool lut_bank_a,
int mpcc_id)
{
struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
union mcm_lut_params m_lut_params = {0};
enum MCM_LUT_XABLE shaper_xable, lut3d_xable = MCM_LUT_DISABLE, lut1d_xable;
enum hubp_3dlut_fl_mode mode;
enum hubp_3dlut_fl_addressing_mode addr_mode;
enum hubp_3dlut_fl_format format = hubp_3dlut_fl_format_unorm_12msb_bitslice;
enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_y_g = hubp_3dlut_fl_crossbar_bit_slice_16_31;
enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cb_b = hubp_3dlut_fl_crossbar_bit_slice_0_15;
enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cr_r = hubp_3dlut_fl_crossbar_bit_slice_32_47;
enum hubp_3dlut_fl_width width = hubp_3dlut_fl_width_17;
struct dc *dc = hubp->ctx->dc;
struct hubp_fl_3dlut_config fl_config;
struct mpc_fl_3dlut_config mpc_fl_config;
struct dc_stream_state *stream = pipe_ctx->stream;
bool bypass_rmcm_shaper = false;
struct dc_rmcm_3dlut *rmcm_3dlut = dc_stream_get_3dlut_for_stream(dc, stream, false);
if (!rmcm_3dlut)
return false;
rmcm_3dlut->protection_bits = mcm_luts->lut3d_data.rmcm_tmz;
dcn42_get_mcm_lut_xable_from_pipe_ctx(dc, pipe_ctx, &shaper_xable, &lut3d_xable, &lut1d_xable);
if (mcm_luts->shaper) {
memset(&m_lut_params, 0, sizeof(m_lut_params));
if (mcm_luts->shaper->type == TF_TYPE_HWPWL) {
m_lut_params.pwl = &mcm_luts->shaper->pwl;
} else if (mcm_luts->shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
ASSERT(false);
cm_helper_translate_curve_to_hw_format(
dc->ctx,
mcm_luts->shaper,
&dpp_base->shaper_params, true);
m_lut_params.pwl = &dpp_base->shaper_params;
}
if (m_lut_params.pwl) {
if (mpc->funcs->rmcm.populate_lut)
mpc->funcs->rmcm.populate_lut(mpc, m_lut_params, lut_bank_a, mpcc_id);
if (mpc->funcs->rmcm.program_lut_mode)
mpc->funcs->rmcm.program_lut_mode(mpc, !bypass_rmcm_shaper, lut_bank_a, mpcc_id);
} else {
return false;
}
}
switch (lut3d_src) {
case DC_CM2_TRANSFER_FUNC_SOURCE_SYSMEM:
memset(&m_lut_params, 0, sizeof(m_lut_params));
break;
case DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM:
fl_get_lut_mode(mcm_luts->lut3d_data.gpu_mem_params.layout,
mcm_luts->lut3d_data.gpu_mem_params.size,
&mode,
&addr_mode,
&width);
if (!dc_is_rmcm_3dlut_supported(hubp, mpc) ||
!mpc->funcs->rmcm.is_config_supported(
(width == hubp_3dlut_fl_width_17 ||
width == hubp_3dlut_fl_width_transformed) ? 17 : 33))
return false;
dc_get_lut_mode(mcm_luts->lut3d_data.gpu_mem_params.layout, &mode, &addr_mode);
dc_get_lut_format(mcm_luts->lut3d_data.gpu_mem_params.format_params.format, &format);
dc_get_lut_xbar(
mcm_luts->lut3d_data.gpu_mem_params.component_order,
&crossbar_bit_slice_cr_r,
&crossbar_bit_slice_y_g,
&crossbar_bit_slice_cb_b);
fl_config.mode = mode;
fl_config.enabled = lut3d_xable != MCM_LUT_DISABLE;
fl_config.address = mcm_luts->lut3d_data.gpu_mem_params.addr;
fl_config.format = format;
fl_config.crossbar_bit_slice_y_g = crossbar_bit_slice_y_g;
fl_config.crossbar_bit_slice_cb_b = crossbar_bit_slice_cb_b;
fl_config.crossbar_bit_slice_cr_r = crossbar_bit_slice_cr_r;
fl_config.width = width;
fl_config.protection_bits = rmcm_3dlut->protection_bits;
fl_config.addr_mode = addr_mode;
fl_config.layout = mcm_luts->lut3d_data.gpu_mem_params.layout;
fl_config.bias = mcm_luts->lut3d_data.gpu_mem_params.format_params.float_params.bias;
fl_config.scale = mcm_luts->lut3d_data.gpu_mem_params.format_params.float_params.scale;
mpc_fl_config.enabled = fl_config.enabled;
mpc_fl_config.width = width;
mpc_fl_config.select_lut_bank_a = lut_bank_a;
mpc_fl_config.bit_depth = mcm_luts->lut3d_data.gpu_mem_params.bit_depth;
mpc_fl_config.hubp_index = hubp->inst;
mpc_fl_config.bias = mcm_luts->lut3d_data.gpu_mem_params.format_params.float_params.bias;
mpc_fl_config.scale = mcm_luts->lut3d_data.gpu_mem_params.format_params.float_params.scale;
mpc->funcs->rmcm.power_on_shaper_3dlut(mpc, mpcc_id, false);
mpc->funcs->rmcm.fl_3dlut_configure(mpc, &mpc_fl_config, mpcc_id);
hubp->funcs->hubp_program_3dlut_fl_config(hubp, &fl_config);
mpc->funcs->rmcm.power_on_shaper_3dlut(mpc, mpcc_id, true);
break;
default:
return false;
}
return true;
}
void dcn42_populate_mcm_luts(struct dc *dc,
struct pipe_ctx *pipe_ctx,
struct dc_cm2_func_luts mcm_luts,
bool lut_bank_a)
{
struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
struct hubp *hubp = pipe_ctx->plane_res.hubp;
int mpcc_id = hubp->inst;
struct mpc *mpc = dc->res_pool->mpc;
union mcm_lut_params m_lut_params;
enum dc_cm2_transfer_func_source lut3d_src = mcm_luts.lut3d_data.lut3d_src;
enum hubp_3dlut_fl_format format = 0;
enum hubp_3dlut_fl_mode mode;
enum hubp_3dlut_fl_width width = 0;
enum hubp_3dlut_fl_addressing_mode addr_mode;
enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_y_g = 0;
enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cb_b = 0;
enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cr_r = 0;
enum MCM_LUT_XABLE shaper_xable = MCM_LUT_DISABLE;
enum MCM_LUT_XABLE lut3d_xable = MCM_LUT_DISABLE;
enum MCM_LUT_XABLE lut1d_xable = MCM_LUT_DISABLE;
bool rval;
dcn42_get_mcm_lut_xable_from_pipe_ctx(dc, pipe_ctx, &shaper_xable, &lut3d_xable, &lut1d_xable);
dcn42_set_mcm_location_post_blend(
dc,
pipe_ctx,
mcm_luts.lut3d_data.mpc_mcm_post_blend);
if (mcm_luts.lut3d_data.rmcm_3dlut_enable &&
is_rmcm_3dlut_fl_supported(dc, mcm_luts.lut3d_data.gpu_mem_params.size)) {
dcn42_program_rmcm_luts(
hubp,
pipe_ctx,
lut3d_src,
&mcm_luts,
mpc,
lut_bank_a,
mpcc_id);
}
if (mcm_luts.lut1d_func) {
memset(&m_lut_params, 0, sizeof(m_lut_params));
if (mcm_luts.lut1d_func->type == TF_TYPE_HWPWL)
m_lut_params.pwl = &mcm_luts.lut1d_func->pwl;
else if (mcm_luts.lut1d_func->type == TF_TYPE_DISTRIBUTED_POINTS) {
rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx,
mcm_luts.lut1d_func,
&dpp_base->regamma_params, false);
m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL;
}
if (m_lut_params.pwl) {
if (mpc->funcs->populate_lut)
mpc->funcs->populate_lut(mpc, MCM_LUT_1DLUT, m_lut_params, lut_bank_a, mpcc_id);
}
if (mpc->funcs->program_lut_mode)
mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, lut1d_xable && m_lut_params.pwl, lut_bank_a, mpcc_id);
}
if (mcm_luts.shaper && mcm_luts.lut3d_data.mpc_3dlut_enable) {
memset(&m_lut_params, 0, sizeof(m_lut_params));
if (mcm_luts.shaper->type == TF_TYPE_HWPWL)
m_lut_params.pwl = &mcm_luts.shaper->pwl;
else if (mcm_luts.shaper->type == TF_TYPE_DISTRIBUTED_POINTS) {
ASSERT(false);
rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx,
mcm_luts.shaper,
&dpp_base->regamma_params, true);
m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL;
}
if (m_lut_params.pwl) {
if (mpc->funcs->mcm.populate_lut)
mpc->funcs->mcm.populate_lut(mpc, m_lut_params, lut_bank_a, mpcc_id);
if (mpc->funcs->program_lut_mode)
mpc->funcs->program_lut_mode(mpc, MCM_LUT_SHAPER, MCM_LUT_ENABLE, lut_bank_a, mpcc_id);
}
}
switch (lut3d_src) {
case DC_CM2_TRANSFER_FUNC_SOURCE_SYSMEM:
memset(&m_lut_params, 0, sizeof(m_lut_params));
if (hubp->funcs->hubp_enable_3dlut_fl)
hubp->funcs->hubp_enable_3dlut_fl(hubp, false);
if (mcm_luts.lut3d_data.lut3d_func && mcm_luts.lut3d_data.lut3d_func->state.bits.initialized) {
m_lut_params.lut3d = &mcm_luts.lut3d_data.lut3d_func->lut_3d;
if (mpc->funcs->populate_lut)
mpc->funcs->populate_lut(mpc, MCM_LUT_3DLUT, m_lut_params, lut_bank_a, mpcc_id);
if (mpc->funcs->program_lut_mode)
mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, lut3d_xable, lut_bank_a,
mpcc_id);
}
break;
case DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM:
switch (mcm_luts.lut3d_data.gpu_mem_params.size) {
case DC_CM2_GPU_MEM_SIZE_333333:
width = hubp_3dlut_fl_width_33;
break;
case DC_CM2_GPU_MEM_SIZE_171717:
width = hubp_3dlut_fl_width_17;
break;
case DC_CM2_GPU_MEM_SIZE_TRANSFORMED:
width = hubp_3dlut_fl_width_transformed;
break;
default:
break;
}
if (mpc->funcs->mcm.is_config_supported &&
!mpc->funcs->mcm.is_config_supported(width))
break;
if (mpc->funcs->program_lut_read_write_control)
mpc->funcs->program_lut_read_write_control(mpc, MCM_LUT_3DLUT, lut_bank_a, mpcc_id);
if (mpc->funcs->program_lut_mode)
mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, lut3d_xable, lut_bank_a, mpcc_id);
if (hubp->funcs->hubp_program_3dlut_fl_addr)
hubp->funcs->hubp_program_3dlut_fl_addr(hubp, mcm_luts.lut3d_data.gpu_mem_params.addr);
if (mpc->funcs->mcm.program_bit_depth)
mpc->funcs->mcm.program_bit_depth(mpc, mcm_luts.lut3d_data.gpu_mem_params.bit_depth, mpcc_id);
dc_get_lut_mode(mcm_luts.lut3d_data.gpu_mem_params.layout, &mode, &addr_mode);
if (hubp->funcs->hubp_program_3dlut_fl_mode)
hubp->funcs->hubp_program_3dlut_fl_mode(hubp, mode);
if (hubp->funcs->hubp_program_3dlut_fl_addressing_mode)
hubp->funcs->hubp_program_3dlut_fl_addressing_mode(hubp, addr_mode);
switch (mcm_luts.lut3d_data.gpu_mem_params.format_params.format) {
case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12MSB:
format = hubp_3dlut_fl_format_unorm_12msb_bitslice;
break;
case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12LSB:
format = hubp_3dlut_fl_format_unorm_12lsb_bitslice;
break;
case DC_CM2_GPU_MEM_FORMAT_16161616_FLOAT_FP1_5_10:
format = hubp_3dlut_fl_format_float_fp1_5_10;
break;
}
if (hubp->funcs->hubp_program_3dlut_fl_format)
hubp->funcs->hubp_program_3dlut_fl_format(hubp, format);
if (hubp->funcs->hubp_update_3dlut_fl_bias_scale &&
mpc->funcs->mcm.program_bias_scale) {
mpc->funcs->mcm.program_bias_scale(mpc,
mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias,
mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale,
mpcc_id);
hubp->funcs->hubp_update_3dlut_fl_bias_scale(hubp,
mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias,
mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale);
}
dc_get_lut_xbar(
mcm_luts.lut3d_data.gpu_mem_params.component_order,
&crossbar_bit_slice_cr_r,
&crossbar_bit_slice_y_g,
&crossbar_bit_slice_cb_b);
if (hubp->funcs->hubp_program_3dlut_fl_crossbar)
hubp->funcs->hubp_program_3dlut_fl_crossbar(hubp,
crossbar_bit_slice_cr_r,
crossbar_bit_slice_y_g,
crossbar_bit_slice_cb_b);
if (mpc->funcs->mcm.program_lut_read_write_control)
mpc->funcs->mcm.program_lut_read_write_control(mpc, MCM_LUT_3DLUT, lut_bank_a, true, mpcc_id);
if (mpc->funcs->mcm.program_3dlut_size)
mpc->funcs->mcm.program_3dlut_size(mpc, width, mpcc_id);
if (mpc->funcs->update_3dlut_fast_load_select)
mpc->funcs->update_3dlut_fast_load_select(mpc, mpcc_id, hubp->inst);
if (hubp->funcs->hubp_enable_3dlut_fl)
hubp->funcs->hubp_enable_3dlut_fl(hubp, true);
else {
if (mpc->funcs->program_lut_mode) {
mpc->funcs->program_lut_mode(mpc, MCM_LUT_SHAPER, MCM_LUT_DISABLE, lut_bank_a, mpcc_id);
mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, MCM_LUT_DISABLE, lut_bank_a, mpcc_id);
mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, MCM_LUT_DISABLE, lut_bank_a, mpcc_id);
}
}
break;
}
}
bool dcn42_set_mcm_luts(struct pipe_ctx *pipe_ctx,
const struct dc_plane_state *plane_state)
{
struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
int mpcc_id = pipe_ctx->plane_res.hubp->inst;
struct dc *dc = pipe_ctx->stream_res.opp->ctx->dc;
struct mpc *mpc = dc->res_pool->mpc;
bool result;
const struct pwl_params *lut_params = NULL;
bool rval;
if (plane_state->mcm_luts.lut3d_data.lut3d_src == DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) {
dcn42_populate_mcm_luts(dc, pipe_ctx, plane_state->mcm_luts, plane_state->lut_bank_a);
return true;
}
mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id);
pipe_ctx->plane_state->mcm_location = MPCC_MOVABLE_CM_LOCATION_BEFORE;
if (plane_state->blend_tf.type == TF_TYPE_HWPWL)
lut_params = &plane_state->blend_tf.pwl;
else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) {
rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
&plane_state->blend_tf,
&dpp_base->regamma_params, false);
lut_params = rval ? &dpp_base->regamma_params : NULL;
}
result = mpc->funcs->program_1dlut(mpc, lut_params, mpcc_id);
lut_params = NULL;
if (plane_state->in_shaper_func.type == TF_TYPE_HWPWL)
lut_params = &plane_state->in_shaper_func.pwl;
else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) {
rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx,
&plane_state->in_shaper_func,
&dpp_base->shaper_params, true);
lut_params = rval ? &dpp_base->shaper_params : NULL;
}
result &= mpc->funcs->program_shaper(mpc, lut_params, mpcc_id);
if (mpc->funcs->program_3dlut) {
if (plane_state->lut3d_func.state.bits.initialized == 1)
result &= mpc->funcs->program_3dlut(mpc, &plane_state->lut3d_func.lut_3d, mpcc_id);
else
result &= mpc->funcs->program_3dlut(mpc, NULL, mpcc_id);
}
return result;
}
void dcn42_hardware_release(struct dc *dc)
{
dcn35_hardware_release(dc);
dc_dmub_srv_release_hw(dc);
}
static int count_active_streams(const struct dc *dc)
{
int i, count = 0;
for (i = 0; i < dc->current_state->stream_count; ++i) {
struct dc_stream_state *stream = dc->current_state->streams[i];
if (stream && (!stream->dpms_off || dc->config.disable_ips_in_dpms_off))
count += 1;
}
return count;
}
void dcn42_calc_blocks_to_gate(struct dc *dc, struct dc_state *context,
struct pg_block_update *update_state)
{
bool hpo_frl_stream_enc_acquired = false;
bool hpo_dp_stream_enc_acquired = false;
unsigned int i = 0;
int j = 0;
memset(update_state, 0, sizeof(struct pg_block_update));
update_state->pg_res_update[PG_DIO] = true;
for (i = 0; i < dc->res_pool->hpo_frl_stream_enc_count; i++) {
if (context->res_ctx.is_hpo_frl_stream_enc_acquired[i] &&
dc->res_pool->hpo_frl_stream_enc[i]) {
hpo_frl_stream_enc_acquired = true;
break;
}
}
for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) {
if (context->res_ctx.is_hpo_dp_stream_enc_acquired[i] &&
dc->res_pool->hpo_dp_stream_enc[i]) {
hpo_dp_stream_enc_acquired = true;
break;
}
}
if (!hpo_frl_stream_enc_acquired && !hpo_dp_stream_enc_acquired)
update_state->pg_res_update[PG_HPO] = true;
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++)
update_state->pg_pipe_res_update[j][i] = true;
if (!pipe_ctx)
continue;
if (pipe_ctx->plane_res.hubp)
update_state->pg_pipe_res_update[PG_HUBP][pipe_ctx->plane_res.hubp->inst] = false;
if (pipe_ctx->plane_res.dpp && pipe_ctx->plane_res.hubp)
update_state->pg_pipe_res_update[PG_DPP][pipe_ctx->plane_res.hubp->inst] = false;
if (pipe_ctx->plane_res.dpp || pipe_ctx->stream_res.opp)
update_state->pg_pipe_res_update[PG_MPCC][pipe_ctx->plane_res.mpcc_inst] = false;
if (pipe_ctx->stream_res.dsc) {
update_state->pg_pipe_res_update[PG_DSC][pipe_ctx->stream_res.dsc->inst] = false;
if (dc->caps.sequential_ono) {
update_state->pg_pipe_res_update[PG_HUBP][pipe_ctx->stream_res.dsc->inst] = false;
update_state->pg_pipe_res_update[PG_DPP][pipe_ctx->stream_res.dsc->inst] = false;
}
}
if (pipe_ctx->stream_res.opp)
update_state->pg_pipe_res_update[PG_OPP][pipe_ctx->stream_res.opp->inst] = false;
if (pipe_ctx->stream_res.hpo_dp_stream_enc)
update_state->pg_pipe_res_update[PG_DPSTREAM][pipe_ctx->stream_res.hpo_dp_stream_enc->inst] = false;
if (pipe_ctx->link_res.dio_link_enc) {
update_state->pg_res_update[PG_DIO] = false;
}
if (pipe_ctx->link_res.hpo_dp_link_enc
|| pipe_ctx->link_res.hpo_frl_link_enc) {
update_state->pg_res_update[PG_HPO] = false;
}
}
if (hpo_frl_stream_enc_acquired)
update_state->pg_pipe_res_update[PG_HDMISTREAM][0] = false;
for (i = 0; i < dc->link_count; i++) {
update_state->pg_pipe_res_update[PG_PHYSYMCLK][dc->links[i]->link_enc_hw_inst] = true;
if (dc->links[i]->type != dc_connection_none)
update_state->pg_pipe_res_update[PG_PHYSYMCLK][dc->links[i]->link_enc_hw_inst] = false;
}
for (i = 0; i < dc->res_pool->timing_generator_count; i++) {
struct timing_generator *tg = dc->res_pool->timing_generators[i];
if (tg && tg->funcs->is_tg_enabled(tg)) {
update_state->pg_pipe_res_update[PG_OPTC][i] = false;
} else {
if (dc->res_pool->pg_cntl->funcs->optc_pg_control)
dc->res_pool->pg_cntl->funcs->optc_pg_control(dc->res_pool->pg_cntl, i, false);
}
}
for (i = 0; i < dc->res_pool->hpo_frl_stream_enc_count; i++) {
if (dc->current_state->res_ctx.is_hpo_frl_stream_enc_acquired[i]) {
update_state->pg_res_update[PG_HPO] = false;
break;
}
}
}
void dcn42_prepare_bandwidth(
struct dc *dc,
struct dc_state *context)
{
struct pg_block_update pg_update_state;
if (dc->hwss.calc_blocks_to_ungate) {
dc->hwss.calc_blocks_to_ungate(dc, context, &pg_update_state);
if (dc->hwss.root_clock_control)
dc->hwss.root_clock_control(dc, &pg_update_state, true);
if (dc->hwss.hw_block_power_up)
dc->hwss.hw_block_power_up(dc, &pg_update_state);
}
dcn401_prepare_bandwidth(dc, context);
}
void dcn42_optimize_bandwidth(struct dc *dc, struct dc_state *context)
{
struct pg_block_update pg_update_state;
print_pg_status(dc, __func__, ": before rcg and power up");
dcn401_optimize_bandwidth(dc, context);
if (dc->hwss.calc_blocks_to_gate) {
dc->hwss.calc_blocks_to_gate(dc, context, &pg_update_state);
if (dc->hwss.hw_block_power_down)
dc->hwss.hw_block_power_down(dc, &pg_update_state);
if (dc->hwss.root_clock_control)
dc->hwss.root_clock_control(dc, &pg_update_state, false);
}
print_pg_status(dc, __func__, ": after rcg and power up");
}
void dcn42_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context,
struct pg_block_update *update_state)
{
bool hpo_frl_stream_enc_acquired = false;
bool hpo_dp_stream_enc_acquired = false;
unsigned int i = 0;
int j = 0;
memset(update_state, 0, sizeof(struct pg_block_update));
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *cur_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i];
if (cur_pipe == NULL || new_pipe == NULL)
continue;
if ((!cur_pipe->plane_state && new_pipe->plane_state) ||
(!cur_pipe->stream && new_pipe->stream) ||
(cur_pipe->stream != new_pipe->stream && new_pipe->stream)) {
for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++) {
if (j == PG_HUBP && new_pipe->plane_res.hubp)
update_state->pg_pipe_res_update[j][new_pipe->plane_res.hubp->inst] = true;
if (j == PG_DPP && new_pipe->plane_res.dpp)
update_state->pg_pipe_res_update[j][new_pipe->plane_res.dpp->inst] = true;
if (j == PG_MPCC && new_pipe->plane_res.dpp)
update_state->pg_pipe_res_update[j][new_pipe->plane_res.mpcc_inst] = true;
if (j == PG_DSC && new_pipe->stream_res.dsc)
update_state->pg_pipe_res_update[j][new_pipe->stream_res.dsc->inst] = true;
if (j == PG_OPP && new_pipe->stream_res.opp)
update_state->pg_pipe_res_update[j][new_pipe->stream_res.opp->inst] = true;
if (j == PG_OPTC && new_pipe->stream_res.tg)
update_state->pg_pipe_res_update[j][new_pipe->stream_res.tg->inst] = true;
if (j == PG_DPSTREAM && new_pipe->stream_res.hpo_dp_stream_enc)
update_state->pg_pipe_res_update[j][new_pipe->stream_res.hpo_dp_stream_enc->inst] = true;
}
} else if (cur_pipe->plane_state == new_pipe->plane_state ||
cur_pipe == new_pipe) {
for (j = 0; j < PG_HW_PIPE_RESOURCES_NUM_ELEMENT; j++) {
if (j == PG_HUBP &&
cur_pipe->plane_res.hubp != new_pipe->plane_res.hubp &&
new_pipe->plane_res.hubp)
update_state->pg_pipe_res_update[j][new_pipe->plane_res.hubp->inst] = true;
if (j == PG_DPP &&
cur_pipe->plane_res.dpp != new_pipe->plane_res.dpp &&
new_pipe->plane_res.dpp)
update_state->pg_pipe_res_update[j][new_pipe->plane_res.dpp->inst] = true;
if (j == PG_OPP &&
cur_pipe->stream_res.opp != new_pipe->stream_res.opp &&
new_pipe->stream_res.opp)
update_state->pg_pipe_res_update[j][new_pipe->stream_res.opp->inst] = true;
if (j == PG_DSC &&
cur_pipe->stream_res.dsc != new_pipe->stream_res.dsc &&
new_pipe->stream_res.dsc)
update_state->pg_pipe_res_update[j][new_pipe->stream_res.dsc->inst] = true;
if (j == PG_OPTC &&
cur_pipe->stream_res.tg != new_pipe->stream_res.tg &&
new_pipe->stream_res.tg)
update_state->pg_pipe_res_update[j][new_pipe->stream_res.tg->inst] = true;
if (j == PG_DPSTREAM &&
cur_pipe->stream_res.hpo_dp_stream_enc != new_pipe->stream_res.hpo_dp_stream_enc &&
new_pipe->stream_res.hpo_dp_stream_enc)
update_state->pg_pipe_res_update[j][new_pipe->stream_res.hpo_dp_stream_enc->inst] = true;
}
}
}
for (i = 0; i < dc->link_count; i++)
if (dc->links[i]->type != dc_connection_none)
update_state->pg_pipe_res_update[PG_PHYSYMCLK][dc->links[i]->link_enc_hw_inst] = true;
for (i = 0; i < dc->res_pool->stream_enc_count; i++) {
if (dc->current_state->res_ctx.is_stream_enc_acquired[i]) {
update_state->pg_res_update[PG_DIO] = true;
break;
}
}
for (i = 0; i < dc->res_pool->hpo_frl_stream_enc_count; i++) {
if (context->res_ctx.is_hpo_frl_stream_enc_acquired[i] &&
dc->res_pool->hpo_frl_stream_enc[i]) {
hpo_frl_stream_enc_acquired = true;
break;
}
}
for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) {
if (context->res_ctx.is_hpo_dp_stream_enc_acquired[i] &&
dc->res_pool->hpo_dp_stream_enc[i]) {
hpo_dp_stream_enc_acquired = true;
break;
}
}
if (hpo_frl_stream_enc_acquired || hpo_dp_stream_enc_acquired)
update_state->pg_res_update[PG_HPO] = true;
if (hpo_frl_stream_enc_acquired)
update_state->pg_pipe_res_update[PG_HDMISTREAM][0] = true;
if (count_active_streams(dc) > 0) {
update_state->pg_res_update[PG_DCCG] = true;
update_state->pg_res_update[PG_DCIO] = true;
update_state->pg_res_update[PG_DCHUBBUB] = true;
update_state->pg_res_update[PG_DCHVM] = true;
update_state->pg_res_update[PG_DCOH] = true;
}
}
void dcn42_hw_block_power_down(struct dc *dc,
struct pg_block_update *update_state)
{
int i = 0;
int pipe_count = dc->res_pool->pipe_count;
struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl;
bool block_disabled = true;
if (!pg_cntl)
return;
if (dc->debug.ignore_pg)
return;
if (update_state->pg_res_update[PG_HPO]) {
if (pg_cntl->funcs->hpo_pg_control)
pg_cntl->funcs->hpo_pg_control(pg_cntl, false);
}
for (i = pipe_count - 1; i >= 0; i--) {
if (update_state->pg_pipe_res_update[PG_HUBP][i] &&
update_state->pg_pipe_res_update[PG_DPP][i]) {
if (pg_cntl->funcs->hubp_dpp_pg_control)
pg_cntl->funcs->hubp_dpp_pg_control(pg_cntl, i, false);
}
}
if (update_state->pg_res_update[PG_DCHUBBUB]) {
if (pg_cntl->funcs->mem_pg_control)
pg_cntl->funcs->mem_pg_control(pg_cntl, false);
}
for (i = dc->res_pool->res_cap->num_dsc-1; i >= 0; i--) {
if (update_state->pg_pipe_res_update[PG_DSC][i]) {
if (pg_cntl->funcs->dsc_pg_control)
pg_cntl->funcs->dsc_pg_control(pg_cntl, i, false);
}
}
for (i = 0; i < pipe_count; i++) {
if (!update_state->pg_pipe_res_update[PG_MPCC][i] ||
!update_state->pg_pipe_res_update[PG_OPP][i] ||
!update_state->pg_pipe_res_update[PG_OPTC][i]) {
block_disabled = false;
break;
}
}
if (block_disabled) {
if (pg_cntl->funcs->plane_otg_pg_control)
pg_cntl->funcs->plane_otg_pg_control(pg_cntl, false);
}
if (update_state->pg_res_update[PG_DIO]) {
if (pg_cntl->funcs->dio_pg_control)
pg_cntl->funcs->dio_pg_control(pg_cntl, false);
}
if (update_state->pg_res_update[PG_DCCG] &&
update_state->pg_res_update[PG_DCIO] &&
update_state->pg_res_update[PG_DCOH]) {
if (pg_cntl->funcs->io_clk_pg_control)
pg_cntl->funcs->io_clk_pg_control(pg_cntl, false);
}
}
void dcn42_hw_block_power_up(struct dc *dc,
struct pg_block_update *update_state)
{
unsigned int i = 0;
struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl;
bool block_enabled = false;
if (!pg_cntl)
return;
if (dc->debug.ignore_pg)
return;
if (update_state->pg_res_update[PG_DCCG] ||
update_state->pg_res_update[PG_DCIO] ||
update_state->pg_res_update[PG_DCOH]) {
if (pg_cntl->funcs->io_clk_pg_control)
pg_cntl->funcs->io_clk_pg_control(pg_cntl, true);
}
if (update_state->pg_res_update[PG_DIO]) {
if (pg_cntl->funcs->dio_pg_control)
pg_cntl->funcs->dio_pg_control(pg_cntl, true);
}
for (i = 0; i < dc->res_pool->pipe_count; i++) {
if (update_state->pg_pipe_res_update[PG_MPCC][i] ||
update_state->pg_pipe_res_update[PG_OPP][i] ||
update_state->pg_pipe_res_update[PG_OPTC][i]) {
block_enabled = true;
break;
}
}
if (block_enabled) {
if (pg_cntl->funcs->plane_otg_pg_control)
pg_cntl->funcs->plane_otg_pg_control(pg_cntl, true);
}
for (i = 0; i < (unsigned int)dc->res_pool->res_cap->num_dsc; i++) {
if (update_state->pg_pipe_res_update[PG_DSC][i]) {
if (pg_cntl->funcs->dsc_pg_control)
pg_cntl->funcs->dsc_pg_control(pg_cntl, i, true);
}
}
if (update_state->pg_res_update[PG_DCHUBBUB]) {
if (pg_cntl->funcs->mem_pg_control)
pg_cntl->funcs->mem_pg_control(pg_cntl, true);
}
for (i = 0; i < dc->res_pool->pipe_count; i++) {
if (update_state->pg_pipe_res_update[PG_HUBP][i] &&
update_state->pg_pipe_res_update[PG_DPP][i]) {
if (pg_cntl->funcs->hubp_dpp_pg_control)
pg_cntl->funcs->hubp_dpp_pg_control(pg_cntl, i, true);
}
}
if (update_state->pg_res_update[PG_HPO]) {
if (pg_cntl->funcs->hpo_pg_control)
pg_cntl->funcs->hpo_pg_control(pg_cntl, true);
}
}
void dcn42_root_clock_control(struct dc *dc,
struct pg_block_update *update_state, bool power_on)
{
unsigned int i = 0;
struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl;
if (!pg_cntl)
return;
if (power_on) {
for (i = 0; i < dc->res_pool->pipe_count; i++) {
if (update_state->pg_pipe_res_update[PG_HUBP][i] &&
update_state->pg_pipe_res_update[PG_DPP][i]) {
if (dc->hwseq->funcs.dpp_root_clock_control)
dc->hwseq->funcs.dpp_root_clock_control(dc->hwseq, i, power_on);
}
if (update_state->pg_pipe_res_update[PG_DPSTREAM][i])
if (dc->hwseq->funcs.dpstream_root_clock_control)
dc->hwseq->funcs.dpstream_root_clock_control(dc->hwseq, i, power_on);
}
for (i = 0; i < dc->res_pool->dig_link_enc_count; i++)
if (update_state->pg_pipe_res_update[PG_PHYSYMCLK][i])
if (dc->hwseq->funcs.physymclk_root_clock_control)
dc->hwseq->funcs.physymclk_root_clock_control(dc->hwseq, i, power_on);
if (update_state->pg_pipe_res_update[PG_HDMISTREAM][0])
if (dc->hwseq->funcs.hdmistream_root_clock_control)
dc->hwseq->funcs.hdmistream_root_clock_control(dc->hwseq, power_on);
}
for (i = 0; i < (unsigned int)dc->res_pool->res_cap->num_dsc; i++) {
if (update_state->pg_pipe_res_update[PG_DSC][i]) {
if (power_on) {
if (dc->res_pool->dccg->funcs->enable_dsc)
dc->res_pool->dccg->funcs->enable_dsc(dc->res_pool->dccg, i);
} else {
if (dc->res_pool->dccg->funcs->disable_dsc)
dc->res_pool->dccg->funcs->disable_dsc(dc->res_pool->dccg, i);
}
}
}
if (!power_on) {
for (i = 0; i < dc->res_pool->pipe_count; i++) {
if (update_state->pg_pipe_res_update[PG_HUBP][i] &&
update_state->pg_pipe_res_update[PG_DPP][i]) {
if (dc->hwseq->funcs.dpp_root_clock_control)
dc->hwseq->funcs.dpp_root_clock_control(dc->hwseq, i, power_on);
}
if (update_state->pg_pipe_res_update[PG_DPSTREAM][i])
if (dc->hwseq->funcs.dpstream_root_clock_control)
dc->hwseq->funcs.dpstream_root_clock_control(dc->hwseq, i, power_on);
}
for (i = 0; i < dc->res_pool->dig_link_enc_count; i++)
if (update_state->pg_pipe_res_update[PG_PHYSYMCLK][i])
if (dc->hwseq->funcs.physymclk_root_clock_control)
dc->hwseq->funcs.physymclk_root_clock_control(dc->hwseq, i, power_on);
if (update_state->pg_pipe_res_update[PG_HDMISTREAM][0])
if (dc->hwseq->funcs.hdmistream_root_clock_control)
dc->hwseq->funcs.hdmistream_root_clock_control(dc->hwseq, power_on);
}
}
void dcn42_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc)
{
(void)dc;
struct crtc_stereo_flags flags = { 0 };
struct dc_stream_state *stream = pipe_ctx->stream;
dcn10_config_stereo_parameters(stream, &flags);
pipe_ctx->stream_res.opp->funcs->opp_program_stereo(
pipe_ctx->stream_res.opp,
flags.PROGRAM_STEREO == 1,
&stream->timing);
pipe_ctx->stream_res.tg->funcs->program_stereo(
pipe_ctx->stream_res.tg,
&stream->timing,
&flags);
return;
}
void dcn42_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock)
{
union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
if (!dc->ctx || !dc->ctx->dmub_srv)
return;
if (!dc->debug.fams2_config.bits.enable && !dc_dmub_srv_is_cursor_offload_enabled(dc)
&& !dmub_hw_lock_mgr_does_context_require_lock(dc, context))
return;
hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
hw_lock_cmd.bits.lock = lock;
hw_lock_cmd.bits.should_release = !lock;
dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
}
void dcn42_dmub_hw_control_lock_fast(union block_sequence_params *params)
{
struct dc *dc = params->dmub_hw_control_lock_fast_params.dc;
bool lock = params->dmub_hw_control_lock_fast_params.lock;
if (params->dmub_hw_control_lock_fast_params.is_required) {
union dmub_inbox0_cmd_lock_hw hw_lock_cmd = { 0 };
hw_lock_cmd.bits.command_code = DMUB_INBOX0_CMD__HW_LOCK;
hw_lock_cmd.bits.hw_lock_client = HW_LOCK_CLIENT_DRIVER;
hw_lock_cmd.bits.lock = lock;
hw_lock_cmd.bits.should_release = !lock;
dmub_hw_lock_mgr_inbox0_cmd(dc->ctx->dmub_srv, hw_lock_cmd);
}
}
void dcn42_power_down_on_boot(struct dc *dc)
{
struct dc_link *edp_links[MAX_NUM_EDP];
struct dc_link *edp_link = NULL;
unsigned int edp_num;
int i = 0;
dc_get_edp_links(dc, edp_links, &edp_num);
if (edp_num)
edp_link = edp_links[0];
if (edp_link && edp_link->link_enc->funcs->is_dig_enabled &&
edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
dc->hwseq->funcs.edp_backlight_control &&
dc->hwseq->funcs.power_down &&
dc->hwss.edp_power_control) {
dc->hwseq->funcs.edp_backlight_control(edp_link, false);
dc->hwseq->funcs.power_down(dc);
dc->hwss.edp_power_control(edp_link, false);
} else {
for (i = 0; i < dc->link_count; i++) {
struct dc_link *link = dc->links[i];
if (link->link_enc && link->link_enc->funcs->is_dig_enabled &&
link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
dc->hwseq->funcs.power_down) {
dc->hwseq->funcs.power_down(dc);
break;
}
}
}
if (dc->clk_mgr->funcs->set_low_power_state)
dc->clk_mgr->funcs->set_low_power_state(dc->clk_mgr);
}