bool update_dispclk = false;
        bool enter_display_off = false;
        bool dpp_clock_lowered = false;
+       bool update_pstate_unsupported_clk = false;
        struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu;
        bool force_reset = false;
        bool update_uclk = false;
        clk_mgr_base->clks.prev_p_state_change_support = clk_mgr_base->clks.p_state_change_support;
        total_plane_count = clk_mgr_helper_get_active_plane_cnt(dc, context);
        p_state_change_support = new_clocks->p_state_change_support || (total_plane_count == 0);
-       if (should_update_pstate_support(safe_to_lower, p_state_change_support, clk_mgr_base->clks.p_state_change_support)) {
+
+       // invalidate the current P-State forced min in certain dc_mode_softmax situations
+       if (dc->clk_mgr->dc_mode_softmax_enabled && safe_to_lower && !p_state_change_support) {
+               if ((new_clocks->dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000) !=
+                               (clk_mgr_base->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000))
+                       update_pstate_unsupported_clk = true;
+       }
+
+       if (should_update_pstate_support(safe_to_lower, p_state_change_support, clk_mgr_base->clks.p_state_change_support) ||
+                       update_pstate_unsupported_clk) {
                clk_mgr_base->clks.p_state_change_support = p_state_change_support;
 
                /* to disable P-State switching, set UCLK min = max */
-               if (!clk_mgr_base->clks.p_state_change_support)
-                       dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
+               if (!clk_mgr_base->clks.p_state_change_support) {
+                       if (dc->clk_mgr->dc_mode_softmax_enabled &&
+                               new_clocks->dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
+                               dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
+                                       dc->clk_mgr->bw_params->dc_mode_softmax_memclk);
+                       else
+                               dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
                                        clk_mgr_base->bw_params->clk_table.entries[clk_mgr_base->bw_params->clk_table.num_entries - 1].memclk_mhz);
+               }
        }
 
        /* Always update saved value, even if new value not set due to P-State switching unsupported */
                        clk_mgr_base->bw_params->clk_table.entries[clk_mgr_base->bw_params->clk_table.num_entries - 1].memclk_mhz);
 }
 
+static void dcn3_set_max_memclk(struct clk_mgr *clk_mgr_base, unsigned int memclk_mhz)
+{
+       struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+
+       if (!clk_mgr->smu_present)
+               return;
+
+       dcn30_smu_set_hard_max_by_freq(clk_mgr, PPCLK_UCLK, memclk_mhz);
+}
+static void dcn3_set_min_memclk(struct clk_mgr *clk_mgr_base, unsigned int memclk_mhz)
+{
+       struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+
+       if (!clk_mgr->smu_present)
+               return;
+       dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, memclk_mhz);
+}
+
 /* Get current memclk states, update bounding box */
 static void dcn3_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base)
 {
                        &num_levels);
        clk_mgr_base->bw_params->clk_table.num_entries = num_levels ? num_levels : 1;
 
+       clk_mgr_base->bw_params->dc_mode_softmax_memclk = dcn30_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_UCLK);
+
        /* Refresh bounding box */
        clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box(
                        clk_mgr->base.ctx->dc, clk_mgr_base->bw_params);
                .notify_wm_ranges = dcn3_notify_wm_ranges,
                .set_hard_min_memclk = dcn3_set_hard_min_memclk,
                .set_hard_max_memclk = dcn3_set_hard_max_memclk,
+               .set_max_memclk = dcn3_set_max_memclk,
+               .set_min_memclk = dcn3_set_min_memclk,
                .get_memclk_states_from_smu = dcn3_get_memclk_states_from_smu,
                .are_clock_states_equal = dcn3_are_clock_states_equal,
                .enable_pme_wa = dcn3_enable_pme_wa,
 
                        core_link_enable_stream(dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]);
 }
 
+static void blank_and_force_memclk(struct dc *dc, bool apply, unsigned int memclk_mhz)
+{
+       struct dc_state *context = dc->current_state;
+       struct hubp *hubp;
+       struct pipe_ctx *pipe;
+       int i;
+
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               pipe = &context->res_ctx.pipe_ctx[i];
+
+               if (pipe->stream != NULL) {
+                       dc->hwss.disable_pixel_data(dc, pipe, true);
+
+                       // wait for double buffer
+                       pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VACTIVE);
+                       pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VBLANK);
+                       pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VACTIVE);
+
+                       hubp = pipe->plane_res.hubp;
+                       hubp->funcs->set_blank_regs(hubp, true);
+               }
+       }
+
+       dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, memclk_mhz);
+       dc->clk_mgr->funcs->set_min_memclk(dc->clk_mgr, memclk_mhz);
+
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               pipe = &context->res_ctx.pipe_ctx[i];
+
+               if (pipe->stream != NULL) {
+                       dc->hwss.disable_pixel_data(dc, pipe, false);
+
+                       hubp = pipe->plane_res.hubp;
+                       hubp->funcs->set_blank_regs(hubp, false);
+               }
+       }
+}
+
+
+/**
+ * dc_enable_dcmode_clk_limit() - lower clocks in dc (battery) mode
+ * @dc: pointer to dc of the dm calling this
+ * @enable: True = transition to DC mode, false = transition back to AC mode
+ *
+ * Some SoCs define additional clock limits when in DC mode, DM should
+ * invoke this function when the platform undergoes a power source transition
+ * so DC can apply/unapply the limit. This interface may be disruptive to
+ * the onscreen content.
+ *
+ * Context: Triggered by OS through DM interface, or manually by escape calls.
+ * Need to hold a dclock when doing so.
+ *
+ * Return: none (void function)
+ *
+ */
+void dc_enable_dcmode_clk_limit(struct dc *dc, bool enable)
+{
+       uint32_t hw_internal_rev = dc->ctx->asic_id.hw_internal_rev;
+       unsigned int softMax, maxDPM, funcMin;
+       bool p_state_change_support;
+
+       if (!ASICREV_IS_BEIGE_GOBY_P(hw_internal_rev))
+               return;
+
+       softMax = dc->clk_mgr->bw_params->dc_mode_softmax_memclk;
+       maxDPM = dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz;
+       funcMin = (dc->clk_mgr->clks.dramclk_khz + 999) / 1000;
+       p_state_change_support = dc->clk_mgr->clks.p_state_change_support;
+
+       if (enable && !dc->clk_mgr->dc_mode_softmax_enabled) {
+               if (p_state_change_support) {
+                       if (funcMin <= softMax)
+                               dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, softMax);
+                       // else: No-Op
+               } else {
+                       if (funcMin <= softMax)
+                               blank_and_force_memclk(dc, true, softMax);
+                       // else: No-Op
+               }
+       } else if (!enable && dc->clk_mgr->dc_mode_softmax_enabled) {
+               if (p_state_change_support) {
+                       if (funcMin <= softMax)
+                               dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, maxDPM);
+                       // else: No-Op
+               } else {
+                       if (funcMin <= softMax)
+                               blank_and_force_memclk(dc, true, maxDPM);
+                       // else: No-Op
+               }
+       }
+       dc->clk_mgr->dc_mode_softmax_enabled = enable;
+}
 bool dc_is_plane_eligible_for_idle_optimizations(struct dc *dc, struct dc_plane_state *plane,
                struct dc_cursor_attributes *cursor_attr)
 {
 
  */
 void dc_lock_memory_clock_frequency(struct dc *dc);
 
+/* set soft max for memclk, to be used for AC/DC switching clock limitations */
+void dc_enable_dcmode_clk_limit(struct dc *dc, bool enable);
+
 /* cleanup on driver unload */
 void dc_hardware_release(struct dc *dc);
 
 
 }
 
 void hubp2_set_blank(struct hubp *hubp, bool blank)
+{
+       hubp2_set_blank_regs(hubp, blank);
+
+       if (blank) {
+               hubp->mpcc_id = 0xf;
+               hubp->opp_id = OPP_ID_INVALID;
+       }
+}
+
+void hubp2_set_blank_regs(struct hubp *hubp, bool blank)
 {
        struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
        uint32_t blank_en = blank ? 1 : 0;
                                        HUBP_NO_OUTSTANDING_REQ, 1,
                                        1, 200);
                }
-
-               hubp->mpcc_id = 0xf;
-               hubp->opp_id = OPP_ID_INVALID;
        }
 }
 
        .hubp_setup_interdependent = hubp2_setup_interdependent,
        .hubp_set_vm_system_aperture_settings = hubp2_set_vm_system_aperture_settings,
        .set_blank = hubp2_set_blank,
+       .set_blank_regs = hubp2_set_blank_regs,
        .dcc_control = hubp2_dcc_control,
        .mem_program_viewport = min_set_viewport,
        .set_cursor_attributes  = hubp2_cursor_set_attributes,
 
 bool hubp2_is_flip_pending(struct hubp *hubp);
 
 void hubp2_set_blank(struct hubp *hubp, bool blank);
+void hubp2_set_blank_regs(struct hubp *hubp, bool blank);
 
 void hubp2_cursor_set_position(
                struct hubp *hubp,
 
                                        pipe_ctx->pipe_idx);
 }
 
+void dcn20_disable_pixel_data(struct dc *dc, struct pipe_ctx *pipe_ctx, bool blank)
+{
+       dcn20_blank_pixel_data(dc, pipe_ctx, blank);
+}
+
 static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream,
                int opp_cnt)
 {
                                        dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
                                        true);
 
+       if (dc->clk_mgr->dc_mode_softmax_enabled)
+               if (dc->clk_mgr->clks.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
+                               context->bw_ctx.bw.dcn.clk.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
+                       dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->dc_mode_softmax_memclk);
+
        dc->clk_mgr->funcs->update_clocks(
                        dc->clk_mgr,
                        context,
 
 void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
                struct dc_link_settings *link_settings);
 void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx);
+void dcn20_disable_pixel_data(
+               struct dc *dc,
+               struct pipe_ctx *pipe_ctx,
+               bool blank);
 void dcn20_blank_pixel_data(
                struct dc *dc,
                struct pipe_ctx *pipe_ctx,
 
        .hubp_setup_interdependent = hubp2_setup_interdependent,
        .hubp_set_vm_system_aperture_settings = hubp3_set_vm_system_aperture_settings,
        .set_blank = hubp2_set_blank,
+       .set_blank_regs = hubp2_set_blank_regs,
        .dcc_control = hubp3_dcc_control,
        .mem_program_viewport = min_set_viewport,
        .set_cursor_attributes  = hubp2_cursor_set_attributes,
 
        dwb->funcs->enable(dwb, &wb_info->dwb_params);
 }
 
+void dcn30_prepare_bandwidth(struct dc *dc,
+       struct dc_state *context)
+{
+       if (dc->clk_mgr->dc_mode_softmax_enabled)
+               if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
+                               context->bw_ctx.bw.dcn.clk.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
+                       dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz);
+
+       dcn20_prepare_bandwidth(dc, context);
+}
+
 void dcn30_disable_writeback(
                struct dc *dc,
                unsigned int dwb_pipe_inst)
 
 #define __DC_HWSS_DCN30_H__
 
 #include "hw_sequencer_private.h"
-
+#include "dcn20/dcn20_hwseq.h"
 struct dc;
 
 void dcn30_init_hw(struct dc *dc);
                struct dc *dc,
                unsigned int dwb_pipe_inst);
 
+void dcn30_prepare_bandwidth(struct dc *dc,
+       struct dc_state *context);
+
 bool dcn30_mmhubbub_warmup(
        struct dc *dc,
        unsigned int num_dwb,
 
        .enable_audio_stream = dce110_enable_audio_stream,
        .disable_audio_stream = dce110_disable_audio_stream,
        .disable_plane = dcn20_disable_plane,
+       .disable_pixel_data = dcn20_disable_pixel_data,
        .pipe_control_lock = dcn20_pipe_control_lock,
        .interdependent_update_lock = dcn10_lock_all_pipes,
        .cursor_lock = dcn10_cursor_lock,
 
 struct clk_bw_params {
        unsigned int vram_type;
        unsigned int num_channels;
+       unsigned int dispclk_vco_khz;
+       unsigned int dc_mode_softmax_memclk;
        struct clk_limit_table clk_table;
        struct wm_table wm_table;
        struct dummy_pstate_entry dummy_pstate_table[4];
        /* Send message to PMFW to set hard max memclk frequency to highest DPM */
        void (*set_hard_max_memclk)(struct clk_mgr *clk_mgr);
 
+       /* Custom set a memclk freq range*/
+       void (*set_max_memclk)(struct clk_mgr *clk_mgr, unsigned int memclk_mhz);
+       void (*set_min_memclk)(struct clk_mgr *clk_mgr, unsigned int memclk_mhz);
+
        /* Get current memclk states from PMFW, update relevant structures */
        void (*get_memclk_states_from_smu)(struct clk_mgr *clk_mgr);
 
        struct dc_clocks clks;
        bool psr_allow_active_cache;
        bool force_smu_not_present;
+       bool dc_mode_softmax_enabled;
        int dprefclk_khz; // Used by program pixel clock in clock source funcs, need to figureout where this goes
        int dentist_vco_freq_khz;
        struct clk_state_registers_and_bypass boot_snapshot;
 
        bool (*hubp_is_flip_pending)(struct hubp *hubp);
 
        void (*set_blank)(struct hubp *hubp, bool blank);
+       void (*set_blank_regs)(struct hubp *hubp, bool blank);
        void (*set_hubp_blank_en)(struct hubp *hubp, bool blank);
 
        void (*set_cursor_attributes)(
 
        enum dc_status (*apply_ctx_to_hw)(struct dc *dc,
                        struct dc_state *context);
        void (*disable_plane)(struct dc *dc, struct pipe_ctx *pipe_ctx);
+       void (*disable_pixel_data)(struct dc *dc, struct pipe_ctx *pipe_ctx, bool blank);
        void (*apply_ctx_for_surface)(struct dc *dc,
                        const struct dc_stream_state *stream,
                        int num_planes, struct dc_state *context);