--- /dev/null
+From 235fef6c7fd341026eee90cc546e6e8ff8b2c315 Mon Sep 17 00:00:00 2001
+From: Samson Tam <Samson.Tam@amd.com>
+Date: Wed, 11 Jan 2023 13:31:31 -0500
+Subject: drm/amd/display: adjust MALL size available for DCN32 and DCN321
+
+From: Samson Tam <Samson.Tam@amd.com>
+
+commit 235fef6c7fd341026eee90cc546e6e8ff8b2c315 upstream.
+
+[Why]
+MALL size available can vary for different SKUs.
+Use num_chans read from VBIOS to determine the available MALL size we can use
+
+[How]
+Define max_chans for DCN32 and DCN321.
+If num_chans is max_chans, then return max_chans as we can access the
+ entire MALL space.
+Otherwise, define avail_chans as the number of available channels we are
+ allowed instead.
+Return corresponding number of channels back and use this to calculate
+ available MALL size.
+
+Reviewed-by: Nevenko Stupar <Nevenko.Stupar@amd.com>
+Acked-by: Alan Liu <HaoPing.Liu@amd.com>
+Signed-off-by: Samson Tam <Samson.Tam@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c | 62 +++++++++++++++-
+ drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h | 2
+ drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c | 9 ++
+ drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 5 +
+ drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c | 5 +
+ 5 files changed, 78 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
+@@ -2109,13 +2109,19 @@ static bool dcn32_resource_construct(
+ dc->caps.max_cursor_size = 64;
+ dc->caps.min_horizontal_blanking_period = 80;
+ dc->caps.dmdata_alloc_size = 2048;
+- dc->caps.mall_size_per_mem_channel = 0;
++ dc->caps.mall_size_per_mem_channel = 4;
+ dc->caps.mall_size_total = 0;
+ dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8;
+
+ dc->caps.cache_line_size = 64;
+ dc->caps.cache_num_ways = 16;
+- dc->caps.max_cab_allocation_bytes = 67108864; // 64MB = 1024 * 1024 * 64
++
++ /* Calculate the available MALL space */
++ dc->caps.max_cab_allocation_bytes = dcn32_calc_num_avail_chans_for_mall(
++ dc, dc->ctx->dc_bios->vram_info.num_chans) *
++ dc->caps.mall_size_per_mem_channel * 1024 * 1024;
++ dc->caps.mall_size_total = dc->caps.max_cab_allocation_bytes;
++
+ dc->caps.subvp_fw_processing_delay_us = 15;
+ dc->caps.subvp_prefetch_end_to_mall_start_us = 15;
+ dc->caps.subvp_swath_height_margin_lines = 16;
+@@ -2545,3 +2551,55 @@ struct pipe_ctx *dcn32_acquire_idle_pipe
+
+ return idle_pipe;
+ }
++
++unsigned int dcn32_calc_num_avail_chans_for_mall(struct dc *dc, int num_chans)
++{
++ /*
++ * DCN32 and DCN321 SKUs may have different sizes for MALL
++ * but we may not be able to access all the MALL space.
++ * If the num_chans is power of 2, then we can access all
++ * of the available MALL space. Otherwise, we can only
++ * access:
++ *
++ * max_cab_size_in_bytes = total_cache_size_in_bytes *
++ * ((2^floor(log2(num_chans)))/num_chans)
++ *
++ * Calculating the MALL sizes for all available SKUs, we
++ * have come up with the follow simplified check.
++ * - we have max_chans which provides the max MALL size.
++ * Each chans supports 4MB of MALL so:
++ *
++ * total_cache_size_in_bytes = max_chans * 4 MB
++ *
++ * - we have avail_chans which shows the number of channels
++ * we can use if we can't access the entire MALL space.
++ * It is generally half of max_chans
++ * - so we use the following checks:
++ *
++ * if (num_chans == max_chans), return max_chans
++ * if (num_chans < max_chans), return avail_chans
++ *
++ * - exception is GC_11_0_0 where we can't access max_chans,
++ * so we define max_avail_chans as the maximum available
++ * MALL space
++ *
++ */
++ int gc_11_0_0_max_chans = 48;
++ int gc_11_0_0_max_avail_chans = 32;
++ int gc_11_0_0_avail_chans = 16;
++ int gc_11_0_3_max_chans = 16;
++ int gc_11_0_3_avail_chans = 8;
++ int gc_11_0_2_max_chans = 8;
++ int gc_11_0_2_avail_chans = 4;
++
++ if (ASICREV_IS_GC_11_0_0(dc->ctx->asic_id.hw_internal_rev)) {
++ return (num_chans == gc_11_0_0_max_chans) ?
++ gc_11_0_0_max_avail_chans : gc_11_0_0_avail_chans;
++ } else if (ASICREV_IS_GC_11_0_2(dc->ctx->asic_id.hw_internal_rev)) {
++ return (num_chans == gc_11_0_2_max_chans) ?
++ gc_11_0_2_max_chans : gc_11_0_2_avail_chans;
++ } else { // if (ASICREV_IS_GC_11_0_3(dc->ctx->asic_id.hw_internal_rev)) {
++ return (num_chans == gc_11_0_3_max_chans) ?
++ gc_11_0_3_max_chans : gc_11_0_3_avail_chans;
++ }
++}
+--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
++++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
+@@ -144,6 +144,8 @@ void dcn32_restore_mall_state(struct dc
+
+ bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe);
+
++unsigned int dcn32_calc_num_avail_chans_for_mall(struct dc *dc, int num_chans);
++
+ /* definitions for run time init of reg offsets */
+
+ /* CLK SRC */
+--- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
++++ b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c
+@@ -1697,11 +1697,18 @@ static bool dcn321_resource_construct(
+ dc->caps.max_cursor_size = 64;
+ dc->caps.min_horizontal_blanking_period = 80;
+ dc->caps.dmdata_alloc_size = 2048;
+- dc->caps.mall_size_per_mem_channel = 0;
++ dc->caps.mall_size_per_mem_channel = 4;
+ dc->caps.mall_size_total = 0;
+ dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8;
+ dc->caps.cache_line_size = 64;
+ dc->caps.cache_num_ways = 16;
++
++ /* Calculate the available MALL space */
++ dc->caps.max_cab_allocation_bytes = dcn32_calc_num_avail_chans_for_mall(
++ dc, dc->ctx->dc_bios->vram_info.num_chans) *
++ dc->caps.mall_size_per_mem_channel * 1024 * 1024;
++ dc->caps.mall_size_total = dc->caps.max_cab_allocation_bytes;
++
+ dc->caps.max_cab_allocation_bytes = 33554432; // 32MB = 1024 * 1024 * 32
+ dc->caps.subvp_fw_processing_delay_us = 15;
+ dc->caps.subvp_prefetch_end_to_mall_start_us = 15;
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+@@ -2381,8 +2381,11 @@ void dcn32_update_bw_bounding_box_fpu(st
+ }
+
+ /* Override from VBIOS for num_chan */
+- if (dc->ctx->dc_bios->vram_info.num_chans)
++ if (dc->ctx->dc_bios->vram_info.num_chans) {
+ dcn3_2_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
++ dcn3_2_soc.mall_allocated_for_dcn_mbytes = (double)(dcn32_calc_num_avail_chans_for_mall(dc,
++ dc->ctx->dc_bios->vram_info.num_chans) * dc->caps.mall_size_per_mem_channel);
++ }
+
+ if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
+ dcn3_2_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn321/dcn321_fpu.c
+@@ -534,8 +534,11 @@ void dcn321_update_bw_bounding_box_fpu(s
+ }
+
+ /* Override from VBIOS for num_chan */
+- if (dc->ctx->dc_bios->vram_info.num_chans)
++ if (dc->ctx->dc_bios->vram_info.num_chans) {
+ dcn3_21_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
++ dcn3_21_soc.mall_allocated_for_dcn_mbytes = (double)(dcn32_calc_num_avail_chans_for_mall(dc,
++ dc->ctx->dc_bios->vram_info.num_chans) * dc->caps.mall_size_per_mem_channel);
++ }
+
+ if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
+ dcn3_21_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
--- /dev/null
+From 2ebd1036209c2e7b61e6bc6e5bee4b67c1684ac6 Mon Sep 17 00:00:00 2001
+From: Alvin Lee <Alvin.Lee2@amd.com>
+Date: Wed, 14 Dec 2022 10:12:55 -0500
+Subject: drm/amd/display: Allow subvp on vactive pipes that are 2560x1440@60
+
+From: Alvin Lee <Alvin.Lee2@amd.com>
+
+commit 2ebd1036209c2e7b61e6bc6e5bee4b67c1684ac6 upstream.
+
+Enable subvp on specifically 1440p@60hz displays even though it can
+switch in vactive.
+
+Tested-by: Daniel Wheeler <Daniel.Wheeler@amd.com>
+Reviewed-by: Jun Lei <Jun.Lei@amd.com>
+Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h | 2 +
+ drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 31 +++++++++++++++++-
+ 2 files changed, 32 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
++++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h
+@@ -142,6 +142,8 @@ void dcn32_restore_mall_state(struct dc
+ struct dc_state *context,
+ struct mall_temp_config *temp_config);
+
++bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe);
++
+ /* definitions for run time init of reg offsets */
+
+ /* CLK SRC */
+--- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
++++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
+@@ -676,7 +676,9 @@ static bool dcn32_assign_subvp_pipe(stru
+ */
+ if (pipe->plane_state && !pipe->top_pipe &&
+ pipe->stream->mall_stream_config.type == SUBVP_NONE && refresh_rate < 120 && !pipe->plane_state->address.tmz_surface &&
+- vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0) {
++ (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0 ||
++ (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] > 0 &&
++ dcn32_allow_subvp_with_active_margin(pipe)))) {
+ while (pipe) {
+ num_pipes++;
+ pipe = pipe->bottom_pipe;
+@@ -2558,3 +2560,30 @@ void dcn32_zero_pipe_dcc_fraction(displa
+ pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
+ pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0;
+ }
++
++bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe)
++{
++ bool allow = false;
++ uint32_t refresh_rate = 0;
++
++ /* Allow subvp on displays that have active margin for 2560x1440@60hz displays
++ * only for now. There must be no scaling as well.
++ *
++ * For now we only enable on 2560x1440@60hz displays to enable 4K60 + 1440p60 configs
++ * for p-state switching.
++ */
++ if (pipe->stream && pipe->plane_state) {
++ refresh_rate = (pipe->stream->timing.pix_clk_100hz * 100 +
++ pipe->stream->timing.v_total * pipe->stream->timing.h_total - 1)
++ / (double)(pipe->stream->timing.v_total * pipe->stream->timing.h_total);
++ if (pipe->stream->timing.v_addressable == 1440 &&
++ pipe->stream->timing.h_addressable == 2560 &&
++ refresh_rate >= 55 && refresh_rate <= 65 &&
++ pipe->plane_state->src_rect.height == 1440 &&
++ pipe->plane_state->src_rect.width == 2560 &&
++ pipe->plane_state->dst_rect.height == 1440 &&
++ pipe->plane_state->dst_rect.width == 2560)
++ allow = true;
++ }
++ return allow;
++}