summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/Makefile10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c1866
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h38
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c883
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h549
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mem_input.c1102
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mem_input.h553
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c376
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h135
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c801
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.h622
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c1475
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h47
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c1202
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.h335
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_transform.c1057
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_transform.h416
17 files changed, 11467 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile
new file mode 100644
index 000000000000..2c43ad7a6f3f
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for DCN.
+
+DCN10 = dcn10_resource.o dcn10_ipp.o dcn10_hw_sequencer.o \
+ dcn10_transform.o dcn10_opp.o dcn10_timing_generator.o \
+ dcn10_mem_input.o dcn10_mpc.o
+
+AMD_DAL_DCN10 = $(addprefix $(AMDDALPATH)/dc/dcn10/,$(DCN10))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_DCN10)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
new file mode 100644
index 000000000000..fb4eb4364bc7
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
@@ -0,0 +1,1866 @@
+/*
+ * Copyright 2016 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dm_services.h"
+#include "dc.h"
+#include "core_dc.h"
+#include "core_types.h"
+#include "core_status.h"
+#include "resource.h"
+#include "hw_sequencer.h"
+#include "dcn10_hw_sequencer.h"
+#include "dce110/dce110_hw_sequencer.h"
+#include "abm.h"
+
+#include "dcn10/dcn10_transform.h"
+#include "dcn10/dcn10_mpc.h"
+#include "dcn10/dcn10_timing_generator.h"
+
+#include "mem_input.h"
+#include "timing_generator.h"
+#include "opp.h"
+#include "ipp.h"
+
+#include "dc_bios_types.h"
+
+#include "raven1/DCN/dcn_1_0_offset.h"
+#include "raven1/DCN/dcn_1_0_sh_mask.h"
+#include "vega10/soc15ip.h"
+
+#include "custom_float.h"
+
+
+struct dcn10_hwseq_reg_offsets {
+ uint32_t dchubp;
+ uint32_t dpp;
+ uint32_t otg;
+ uint32_t vtg;
+ uint32_t fmt;
+};
+
+/* TODO: move to resource */
+static const struct dcn10_hwseq_reg_offsets reg_offsets[] = {
+ {
+ .dchubp = (mmHUBP0_DCHUBP_CNTL - mmHUBP0_DCHUBP_CNTL),
+ .dpp = (mmCM0_CM_DGAM_CONTROL - mmCM0_CM_DGAM_CONTROL),
+ .otg = (mmOTG0_OTG_CONTROL - mmOTG0_OTG_CONTROL),
+ .vtg = (mmVTG0_CONTROL - mmVTG0_CONTROL),
+ .fmt = (mmFMT0_FMT_BIT_DEPTH_CONTROL -
+ mmFMT0_FMT_BIT_DEPTH_CONTROL),
+ },
+ {
+ .dchubp = (mmHUBP1_DCHUBP_CNTL - mmHUBP0_DCHUBP_CNTL),
+ .dpp = (mmCM1_CM_DGAM_CONTROL - mmCM0_CM_DGAM_CONTROL),
+ .otg = (mmOTG1_OTG_CONTROL - mmOTG0_OTG_CONTROL),
+ .vtg = (mmVTG1_CONTROL - mmVTG0_CONTROL),
+ .fmt = (mmFMT1_FMT_BIT_DEPTH_CONTROL -
+ mmFMT0_FMT_BIT_DEPTH_CONTROL),
+ },
+ {
+ .dchubp = (mmHUBP2_DCHUBP_CNTL - mmHUBP0_DCHUBP_CNTL),
+ .dpp = (mmCM2_CM_DGAM_CONTROL - mmCM0_CM_DGAM_CONTROL),
+ .otg = (mmOTG2_OTG_CONTROL - mmOTG0_OTG_CONTROL),
+ .vtg = (mmVTG2_CONTROL - mmVTG0_CONTROL),
+ .fmt = (mmFMT2_FMT_BIT_DEPTH_CONTROL -
+ mmFMT0_FMT_BIT_DEPTH_CONTROL),
+ },
+ {
+ .dchubp = (mmHUBP3_DCHUBP_CNTL - mmHUBP0_DCHUBP_CNTL),
+ .dpp = (mmCM3_CM_DGAM_CONTROL - mmCM0_CM_DGAM_CONTROL),
+ .otg = (mmOTG3_OTG_CONTROL - mmOTG0_OTG_CONTROL),
+ .vtg = (mmVTG3_CONTROL - mmVTG0_CONTROL),
+ .fmt = (mmFMT3_FMT_BIT_DEPTH_CONTROL -
+ mmFMT0_FMT_BIT_DEPTH_CONTROL),
+ }
+};
+
+#define HWSEQ_REG_UPDATE_N(reg_name, n, ...) \
+ generic_reg_update_soc15(ctx, inst_offset, reg_name, n, __VA_ARGS__)
+
+#define HWSEQ_REG_SET_N(reg_name, n, ...) \
+ generic_reg_set_soc15(ctx, inst_offset, reg_name, n, __VA_ARGS__)
+
+#define HWSEQ_REG_UPDATE(reg, field, val) \
+ HWSEQ_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
+
+#define HWSEQ_REG_UPDATE_2(reg, field1, val1, field2, val2) \
+ HWSEQ_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
+
+#define HWSEQ_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3) \
+ HWSEQ_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
+
+
+#define HWSEQ_REG_SET(reg, field, val) \
+ HWSEQ_REG_SET_N(reg, 1, FD(reg##__##field), val)
+
+/* TODO should be moved to OTG */
+static void lock_otg_master_update(
+ struct dc_context *ctx,
+ uint8_t inst)
+{
+ uint32_t inst_offset = reg_offsets[inst].otg;
+
+ HWSEQ_REG_UPDATE(OTG0_OTG_GLOBAL_CONTROL0,
+ OTG_MASTER_UPDATE_LOCK_SEL, inst);
+
+ /* unlock master locker */
+ HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK,
+ OTG_MASTER_UPDATE_LOCK, 1);
+
+ /* wait for unlock happens */
+ if (!wait_reg(ctx, inst_offset, OTG0_OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, 1))
+ BREAK_TO_DEBUGGER();
+
+}
+
+static bool unlock_master_tg_and_wait(
+ struct dc_context *ctx,
+ uint8_t inst)
+{
+ uint32_t inst_offset = reg_offsets[inst].otg;
+
+ HWSEQ_REG_UPDATE(OTG0_OTG_GLOBAL_SYNC_STATUS,
+ VUPDATE_NO_LOCK_EVENT_CLEAR, 1);
+ HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, 0);
+
+ if (!wait_reg(ctx, inst_offset, OTG0_OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_EVENT_OCCURRED, 1)) {
+ dm_logger_write(ctx->logger, LOG_ERROR,
+ "wait for VUPDATE_NO_LOCK_EVENT_OCCURRED failed\n");
+ BREAK_TO_DEBUGGER();
+ return false;
+ }
+ return true;
+}
+
+/* TODO: should be moved to OTG ? */
+static void unlock_otg_master(
+ struct dc_context *ctx,
+ uint8_t inst)
+{
+ uint32_t inst_offset = reg_offsets[inst].otg;
+
+ /* unlock master locker */
+ HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK,
+ OTG_MASTER_UPDATE_LOCK, 0);
+}
+
+
+static void wait_no_outstanding_request(
+ struct dc_context *ctx,
+ uint8_t plane_id)
+{
+ uint32_t inst_offset = reg_offsets[plane_id].dchubp;
+
+ if (!wait_reg(ctx, inst_offset, HUBP0_DCHUBP_CNTL, HUBP_NO_OUTSTANDING_REQ, 1))
+ BREAK_TO_DEBUGGER();
+}
+
+static void disable_clocks(
+ struct dc_context *ctx,
+ uint8_t plane_id)
+{
+ uint32_t inst_offset = reg_offsets[plane_id].dchubp;
+
+ generic_reg_update_soc15(ctx, inst_offset, HUBP0_HUBP_CLK_CNTL, 1,
+ FD(HUBP0_HUBP_CLK_CNTL__HUBP_CLOCK_ENABLE), 0);
+
+ inst_offset = reg_offsets[plane_id].dpp;
+ generic_reg_update_soc15(ctx, inst_offset, DPP_TOP0_DPP_CONTROL, 1,
+ FD(DPP_TOP0_DPP_CONTROL__DPP_CLOCK_ENABLE), 0);
+}
+
+/* TODO: This is one time program during system boot up,
+ * this should be done within BIOS or CAIL
+ */
+static void dchubp_map_fb_to_mc(struct dc_context *ctx)
+{
+ /* TODO: do not know where to program
+ * DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB
+ */
+ /*
+ * TODO: For real ASIC, FB_OFFSET may be need change to the same value
+ * as FB_BASE. Need re-visit this for real ASIC.
+ */
+ dm_write_reg_soc15(ctx, mmDCHUBBUB_SDPIF_FB_BASE, 0, 0x80);
+ dm_write_reg_soc15(ctx, mmDCHUBBUB_SDPIF_FB_OFFSET, 0, 0);
+ dm_write_reg_soc15(ctx, mmDCHUBBUB_SDPIF_FB_TOP, 0, 0xFF);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_CFG0, 7,
+ FD(DCHUBBUB_SDPIF_CFG0__SDPIF_DATA_RESPONSE_STATUS_CLEAR), 0,
+ FD(DCHUBBUB_SDPIF_CFG0__SDPIF_REQ_CREDIT_ERROR_CLEAR), 0,
+ FD(DCHUBBUB_SDPIF_CFG0__SDPIF_FLUSH_REQ_CREDIT_EN), 0,
+ FD(DCHUBBUB_SDPIF_CFG0__SDPIF_REQ_CREDIT_EN), 0,
+ FD(DCHUBBUB_SDPIF_CFG0__SDPIF_PORT_CONTROL), 1,
+ FD(DCHUBBUB_SDPIF_CFG0__SDPIF_UNIT_ID_BITMASK), 0xd3,
+ FD(DCHUBBUB_SDPIF_CFG0__SDPIF_CREDIT_DISCONNECT_DELAY), 0xc);
+
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_CFG1, 4,
+ FD(DCHUBBUB_SDPIF_CFG1__SDPIF_INSIDE_FB_IO), 0,
+ FD(DCHUBBUB_SDPIF_CFG1__SDPIF_INSIDE_FB_VC), 6,
+ FD(DCHUBBUB_SDPIF_CFG1__SDPIF_OUTSIDE_FB_IO), 1,
+ FD(DCHUBBUB_SDPIF_CFG1__SDPIF_OUTSIDE_FB_VC), 6);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_FB_BASE, 1,
+ FD(DCHUBBUB_SDPIF_FB_BASE__SDPIF_FB_BASE), 0x000080);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_FB_TOP, 1,
+ FD(DCHUBBUB_SDPIF_FB_TOP__SDPIF_FB_TOP), 0x0000ff);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_AGP_BOT, 1,
+ FD(DCHUBBUB_SDPIF_AGP_BOT__SDPIF_AGP_BOT), 0x0000040);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_AGP_TOP, 1,
+ FD(DCHUBBUB_SDPIF_AGP_TOP__SDPIF_AGP_TOP), 0x00001ff);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_AGP_BASE, 1,
+ FD(DCHUBBUB_SDPIF_AGP_BASE__SDPIF_AGP_BASE), 0x0000080);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_APER_TOP, 1,
+ FD(DCHUBBUB_SDPIF_APER_TOP__SDPIF_APER_TOP), 0x00007ff);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_APER_DEF_0, 1,
+ FD(DCHUBBUB_SDPIF_APER_DEF_0__SDPIF_APER_DEF_0), 0xdeadbeef);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_0, 2,
+ FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_0__SDPIF_MARC_EN_0), 0,
+ FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_0__SDPIF_MARC_RELOC_LO_0), 0x90000);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_0, 1,
+ FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_0__SDPIF_MARC_LENGTH_LO_0), 0x10000);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_BASE_LO_1, 1,
+ FD(DCHUBBUB_SDPIF_MARC_BASE_LO_1__SDPIF_MARC_BASE_LO_1), 0x10000);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_1, 2,
+ FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_1__SDPIF_MARC_EN_1), 0,
+ FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_1__SDPIF_MARC_RELOC_LO_1), 0xa0000);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_1, 1,
+ FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_1__SDPIF_MARC_LENGTH_LO_1), 0x10000);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_BASE_LO_2, 1,
+ FD(DCHUBBUB_SDPIF_MARC_BASE_LO_2__SDPIF_MARC_BASE_LO_2), 0x20000);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_2, 2,
+ FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_2__SDPIF_MARC_EN_2), 0,
+ FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_2__SDPIF_MARC_RELOC_LO_2), 0xb0000);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_2, 1,
+ FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_2__SDPIF_MARC_LENGTH_LO_2), 0x10000);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_BASE_LO_3, 1,
+ FD(DCHUBBUB_SDPIF_MARC_BASE_LO_3__SDPIF_MARC_BASE_LO_3), 0x30000);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_RELOC_LO_3, 2,
+ FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_3__SDPIF_MARC_EN_3), 0,
+ FD(DCHUBBUB_SDPIF_MARC_RELOC_LO_3__SDPIF_MARC_RELOC_LO_3), 0xc0000);
+
+ generic_reg_set_soc15(ctx, 0, DCHUBBUB_SDPIF_MARC_LENGTH_LO_3, 1,
+ FD(DCHUBBUB_SDPIF_MARC_LENGTH_LO_3__SDPIF_MARC_LENGTH_LO_3), 0x10000);
+
+ /* TODO: Is DCN_VM_SYSTEM_APERTURE address one time programming?
+ * Are all 4 hubp programmed with the same address?
+ */
+ dm_write_reg_soc15(ctx, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, 0, 0x80000);
+ dm_write_reg_soc15(ctx, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, 0, 0);
+ dm_write_reg_soc15(ctx, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, 0, 0x100000);
+ dm_write_reg_soc15(ctx, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, 0, 0);
+ dm_write_reg_soc15(ctx, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, 0, 0x80000);
+ dm_write_reg_soc15(ctx, mmHUBPREQ0_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, 0, 0);
+
+ dm_write_reg_soc15(ctx, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, 0, 0x80000);
+ dm_write_reg_soc15(ctx, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, 0, 0);
+ dm_write_reg_soc15(ctx, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, 0, 0x100000);
+ dm_write_reg_soc15(ctx, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, 0, 0);
+ dm_write_reg_soc15(ctx, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, 0, 0x80000);
+ dm_write_reg_soc15(ctx, mmHUBPREQ1_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, 0, 0);
+
+ dm_write_reg_soc15(ctx, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, 0, 0x80000);
+ dm_write_reg_soc15(ctx, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, 0, 0);
+ dm_write_reg_soc15(ctx, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, 0, 0x100000);
+ dm_write_reg_soc15(ctx, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, 0, 0);
+ dm_write_reg_soc15(ctx, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, 0, 0x80000);
+ dm_write_reg_soc15(ctx, mmHUBPREQ2_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, 0, 0);
+
+ dm_write_reg_soc15(ctx, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, 0, 0x80000);
+ dm_write_reg_soc15(ctx, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, 0, 0);
+ dm_write_reg_soc15(ctx, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, 0, 0x100000);
+ dm_write_reg_soc15(ctx, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, 0, 0);
+ dm_write_reg_soc15(ctx, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, 0, 0x80000);
+ dm_write_reg_soc15(ctx, mmHUBPREQ3_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, 0, 0);
+}
+
+/* TODO: This is one time program during system boot up,
+ * this should be done within BIOS
+ */
+static void dchubup_setup_timer(struct dc_context *ctx)
+{
+ dm_write_reg_soc15(ctx, mmREFCLK_CNTL, 0, 0);
+
+ generic_reg_update_soc15(ctx, 0, DCHUBBUB_GLOBAL_TIMER_CNTL, 1,
+ FD(DCHUBBUB_GLOBAL_TIMER_CNTL__DCHUBBUB_GLOBAL_TIMER_ENABLE), 1);
+}
+
+/* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
+ * VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
+ * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
+ */
+static void select_vtg(
+ struct dc_context *ctx,
+ uint8_t plane_id,
+ uint8_t inst)
+{
+ uint32_t inst_offset = reg_offsets[plane_id].dchubp;
+
+ HWSEQ_REG_UPDATE(HUBP0_DCHUBP_CNTL, HUBP_VTG_SEL, inst);
+}
+
+static void enable_dcfclk(
+ struct dc_context *ctx,
+ uint8_t plane_id,
+ uint32_t requested_pix_clk,
+ bool dppclk_div)
+{
+ uint32_t inst_offset = reg_offsets[plane_id].dchubp;
+
+ HWSEQ_REG_UPDATE(HUBP0_HUBP_CLK_CNTL, HUBP_CLOCK_ENABLE, 1);
+}
+
+static void enable_dppclk(
+ struct dc_context *ctx,
+ uint8_t plane_id,
+ uint32_t requested_pix_clk,
+ bool dppclk_div)
+{
+ uint32_t inst_offset = reg_offsets[plane_id].dpp;
+
+ dm_logger_write(ctx->logger, LOG_SURFACE,
+ "dppclk_rate_control for pipe %d programed to %d\n",
+ plane_id,
+ dppclk_div);
+
+ /* TODO: find condition for DPP clock to DISPCLK or 1/2 DISPCLK */
+ if (dppclk_div) {
+ /* 1/2 DISPCLK*/
+ HWSEQ_REG_UPDATE_2(DPP_TOP0_DPP_CONTROL,
+ DPPCLK_RATE_CONTROL, 1,
+ DPP_CLOCK_ENABLE, 1);
+ } else {
+ /* DISPCLK */
+ HWSEQ_REG_UPDATE_2(DPP_TOP0_DPP_CONTROL,
+ DPPCLK_RATE_CONTROL, 0,
+ DPP_CLOCK_ENABLE, 1);
+ }
+}
+
+static void enable_power_gating_plane(
+ struct dc_context *ctx,
+ bool enable)
+{
+ uint32_t inst_offset = 0; /* each register only has one instance */
+ bool force_on = 1; /* disable power gating */
+
+ if (enable)
+ force_on = 0;
+
+ /* DCHUBP0/1/2/3 */
+ HWSEQ_REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on);
+ HWSEQ_REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on);
+ HWSEQ_REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on);
+ HWSEQ_REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on);
+
+ /* DPP0/1/2/3 */
+ HWSEQ_REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on);
+ HWSEQ_REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on);
+ HWSEQ_REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on);
+ HWSEQ_REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on);
+
+ if (ctx->dc->debug.disable_clock_gate) {
+ /* probably better to just write entire register to 0xffff to
+ * ensure all clock gating is disabled
+ */
+ HWSEQ_REG_UPDATE_3(DCCG_GATE_DISABLE_CNTL,
+ DISPCLK_R_DCCG_GATE_DISABLE, 1,
+ DPREFCLK_R_DCCG_GATE_DISABLE, 1,
+ REFCLK_R_DIG_GATE_DISABLE, 1);
+ HWSEQ_REG_UPDATE(DCFCLK_CNTL,
+ DCFCLK_GATE_DIS, 1);
+ }
+
+}
+
+static void dpp_pg_control(
+ struct dc_context *ctx,
+ unsigned int dpp_inst,
+ bool power_on)
+{
+ uint32_t inst_offset = 0;
+ uint32_t power_gate = power_on ? 0 : 1;
+ uint32_t pwr_status = power_on ? 0 : 2;
+
+ if (ctx->dc->debug.disable_dpp_power_gate)
+ return;
+
+ switch (dpp_inst) {
+ case 0: /* DPP0 */
+ HWSEQ_REG_UPDATE(DOMAIN1_PG_CONFIG,
+ DOMAIN1_POWER_GATE, power_gate);
+
+ wait_reg(ctx, 0, DOMAIN1_PG_STATUS,
+ DOMAIN1_PGFSM_PWR_STATUS, pwr_status);
+ break;
+ case 1: /* DPP1 */
+ HWSEQ_REG_UPDATE(DOMAIN3_PG_CONFIG,
+ DOMAIN3_POWER_GATE, power_gate);
+
+ wait_reg(ctx, 0, DOMAIN3_PG_STATUS,
+ DOMAIN3_PGFSM_PWR_STATUS, pwr_status);
+ break;
+ case 2: /* DPP2 */
+ HWSEQ_REG_UPDATE(DOMAIN5_PG_CONFIG,
+ DOMAIN5_POWER_GATE, power_gate);
+
+ wait_reg(ctx, 0, DOMAIN5_PG_STATUS,
+ DOMAIN5_PGFSM_PWR_STATUS, pwr_status);
+ break;
+ case 3: /* DPP3 */
+ HWSEQ_REG_UPDATE(DOMAIN7_PG_CONFIG,
+ DOMAIN7_POWER_GATE, power_gate);
+
+ wait_reg(ctx, 0, DOMAIN7_PG_STATUS,
+ DOMAIN7_PGFSM_PWR_STATUS, pwr_status);
+ break;
+ default:
+ BREAK_TO_DEBUGGER();
+ break;
+ }
+}
+
+static void hubp_pg_control(
+ struct dc_context *ctx,
+ unsigned int hubp_inst,
+ bool power_on)
+{
+ uint32_t inst_offset = 0;
+ uint32_t power_gate = power_on ? 0 : 1;
+ uint32_t pwr_status = power_on ? 0 : 2;
+
+ if (ctx->dc->debug.disable_hubp_power_gate)
+ return;
+
+ switch (hubp_inst) {
+ case 0: /* DCHUBP0 */
+ HWSEQ_REG_UPDATE(DOMAIN0_PG_CONFIG,
+ DOMAIN0_POWER_GATE, power_gate);
+
+ wait_reg(ctx, 0, DOMAIN0_PG_STATUS,
+ DOMAIN0_PGFSM_PWR_STATUS, pwr_status);
+ break;
+ case 1: /* DCHUBP1 */
+ HWSEQ_REG_UPDATE(DOMAIN2_PG_CONFIG,
+ DOMAIN2_POWER_GATE, power_gate);
+
+ wait_reg(ctx, 0, DOMAIN2_PG_STATUS,
+ DOMAIN2_PGFSM_PWR_STATUS, pwr_status);
+ break;
+ case 2: /* DCHUBP2 */
+ HWSEQ_REG_UPDATE(DOMAIN4_PG_CONFIG,
+ DOMAIN4_POWER_GATE, power_gate);
+
+ wait_reg(ctx, 0, DOMAIN4_PG_STATUS,
+ DOMAIN4_PGFSM_PWR_STATUS, pwr_status);
+ break;
+ case 3: /* DCHUBP3 */
+ HWSEQ_REG_UPDATE(DOMAIN6_PG_CONFIG,
+ DOMAIN6_POWER_GATE, power_gate);
+
+ wait_reg(ctx, 0, DOMAIN6_PG_STATUS,
+ DOMAIN6_PGFSM_PWR_STATUS, pwr_status);
+ break;
+ default:
+ BREAK_TO_DEBUGGER();
+ break;
+ }
+}
+
+static void power_on_plane(
+ struct dc_context *ctx,
+ uint8_t plane_id,
+ uint8_t inst)
+{
+ uint32_t inst_offset = 0;
+
+ /* disable clock power gating */
+
+ /* DCCG_GATE_DISABLE_CNTL only has one instance */
+ HWSEQ_REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL,
+ DISPCLK_DCCG_GATE_DISABLE, 1,
+ DPPCLK_GATE_DISABLE, 1);
+ /* DCFCLK_CNTL only has one instance */
+ HWSEQ_REG_UPDATE(DCFCLK_CNTL,
+ DCFCLK_GATE_DIS, 1);
+
+ HWSEQ_REG_SET(DC_IP_REQUEST_CNTL,
+ IP_REQUEST_EN, 1);
+ dpp_pg_control(ctx, plane_id, true);
+ hubp_pg_control(ctx, plane_id, true);
+ HWSEQ_REG_SET(DC_IP_REQUEST_CNTL,
+ IP_REQUEST_EN, 0);
+
+ if (ctx->dc->debug.disable_clock_gate) {
+ HWSEQ_REG_UPDATE(DCCG_GATE_DISABLE_CNTL,
+ DISPCLK_DCCG_GATE_DISABLE, 0);
+ } else {
+ /* DCCG_GATE_DISABLE_CNTL only has one instance. inst_offset = 0 */
+ HWSEQ_REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL,
+ DISPCLK_DCCG_GATE_DISABLE, 0,
+ DPPCLK_GATE_DISABLE, 0);
+ /* DCFCLK_CNTL only has one instance. inst_offset = 0 */
+ HWSEQ_REG_UPDATE(DCFCLK_CNTL,
+ DCFCLK_GATE_DIS, 0);
+ }
+}
+
+/* fully check bios enabledisplaypowergating table. dal only need dce init
+ * other power, clock gate register will be handle by dal itself.
+ * further may be put within init_hw
+ */
+static bool dcn10_enable_display_power_gating(
+ struct core_dc *dc,
+ uint8_t controller_id,
+ struct dc_bios *dcb,
+ enum pipe_gating_control power_gating)
+{
+ /* TODOFPGA */
+#if 0
+ if (power_gating != PIPE_GATING_CONTROL_ENABLE)
+ dce110_init_pte(ctx);
+#endif
+
+ return true;
+}
+
+static void bios_golden_init(struct core_dc *dc)
+{
+ struct dc_bios *bp = dc->ctx->dc_bios;
+ int i;
+
+ /* initialize dcn global */
+ bp->funcs->enable_disp_power_gating(bp,
+ CONTROLLER_ID_D0, ASIC_PIPE_INIT);
+
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ /* initialize dcn per pipe */
+ bp->funcs->enable_disp_power_gating(bp,
+ CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE);
+ }
+}
+
+static void init_hw(struct core_dc *dc)
+{
+ int i;
+ struct dc_bios *bp;
+ struct transform *xfm;
+ struct abm *abm;
+
+ bp = dc->ctx->dc_bios;
+
+ if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+ /* TODO: this will be moved to Diag or BIOS */
+ dchubup_setup_timer(dc->ctx);
+
+ /* TODO: dchubp_map_fb_to_mc will be moved to dchub interface
+ * between dc and kmd
+ */
+ dchubp_map_fb_to_mc(dc->ctx);
+
+ enable_power_gating_plane(dc->ctx, true);
+ return;
+ }
+ /* end of FPGA. Below if real ASIC */
+
+ bios_golden_init(dc);
+
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ xfm = dc->res_pool->transforms[i];
+ xfm->funcs->transform_reset(xfm);
+
+ /* TODOFPGA: may need later */
+#if 0
+ xfm->funcs->transform_power_up(xfm);
+ dc->hwss.enable_display_pipe_clock_gating(
+ dc->ctx,
+ true);
+#endif
+ }
+ /* TODOFPGA: light sleep */
+#if 0
+ dc->hwss.clock_gating_power_up(dc->ctx, false);
+#endif
+
+ for (i = 0; i < dc->link_count; i++) {
+ /* Power up AND update implementation according to the
+ * required signal (which may be different from the
+ * default signal on connector).
+ */
+ struct core_link *link = dc->links[i];
+
+ link->link_enc->funcs->hw_init(link->link_enc);
+ }
+
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct timing_generator *tg =
+ dc->res_pool->timing_generators[i];
+
+ tg->funcs->disable_vga(tg);
+
+ /* Blank controller using driver code instead of
+ * command table.
+ */
+ tg->funcs->set_blank(tg, true);
+ hwss_wait_for_blank_complete(tg);
+ }
+
+ for (i = 0; i < dc->res_pool->audio_count; i++) {
+ struct audio *audio = dc->res_pool->audios[i];
+
+ audio->funcs->hw_init(audio);
+ }
+
+ abm = dc->res_pool->abm;
+ if (abm != NULL) {
+ abm->funcs->init_backlight(abm);
+ abm->funcs->abm_init(abm);
+ }
+
+ /* power AFMT HDMI memory TODO: may move to dis/en output save power*/
+ generic_reg_set_soc15(dc->ctx, 0, DIO_MEM_PWR_CTRL, 7,
+ FD(DIO_MEM_PWR_CTRL__HDMI0_MEM_PWR_FORCE), 0,
+ FD(DIO_MEM_PWR_CTRL__HDMI1_MEM_PWR_FORCE), 0,
+ FD(DIO_MEM_PWR_CTRL__HDMI2_MEM_PWR_FORCE), 0,
+ FD(DIO_MEM_PWR_CTRL__HDMI3_MEM_PWR_FORCE), 0,
+ FD(DIO_MEM_PWR_CTRL__HDMI4_MEM_PWR_FORCE), 0,
+ FD(DIO_MEM_PWR_CTRL__HDMI5_MEM_PWR_FORCE), 0,
+ FD(DIO_MEM_PWR_CTRL__HDMI6_MEM_PWR_FORCE), 0);
+
+ /* This power gating should be one-time program for DAL.
+ * It can only change by registry key
+ * TODO: new task will for this.
+ * if power gating is disable, power_on_plane and power_off_plane
+ * should be skip. Otherwise, hand will be met in power_off_plane
+ */
+
+ enable_power_gating_plane(dc->ctx, true);
+}
+
+static enum dc_status dcn10_prog_pixclk_crtc_otg(
+ struct pipe_ctx *pipe_ctx,
+ struct validate_context *context,
+ struct core_dc *dc)
+{
+ struct core_stream *stream = pipe_ctx->stream;
+ enum dc_color_space color_space;
+ struct tg_color black_color = {0};
+ bool enableStereo = stream->public.timing.timing_3d_format == TIMING_3D_FORMAT_NONE ?
+ false:true;
+ bool rightEyePolarity = stream->public.timing.flags.RIGHT_EYE_3D_POLARITY;
+
+
+ /* by upper caller loop, pipe0 is parent pipe and be called first.
+ * back end is set up by for pipe0. Other children pipe share back end
+ * with pipe 0. No program is needed.
+ */
+ if (pipe_ctx->top_pipe != NULL)
+ return DC_OK;
+
+ /* TODO check if timing_changed, disable stream if timing changed */
+
+ /* HW program guide assume display already disable
+ * by unplug sequence. OTG assume stop.
+ */
+ pipe_ctx->tg->funcs->enable_optc_clock(pipe_ctx->tg, true);
+
+ if (false == pipe_ctx->clock_source->funcs->program_pix_clk(
+ pipe_ctx->clock_source,
+ &pipe_ctx->pix_clk_params,
+ &pipe_ctx->pll_settings)) {
+ BREAK_TO_DEBUGGER();
+ return DC_ERROR_UNEXPECTED;
+ }
+ pipe_ctx->tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset;
+ pipe_ctx->tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start;
+ pipe_ctx->tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset;
+ pipe_ctx->tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width;
+
+ pipe_ctx->tg->dlg_otg_param.signal = pipe_ctx->stream->signal;
+
+ pipe_ctx->tg->funcs->program_timing(
+ pipe_ctx->tg,
+ &stream->public.timing,
+ true);
+
+ pipe_ctx->opp->funcs->opp_set_stereo_polarity(
+ pipe_ctx->opp,
+ enableStereo,
+ rightEyePolarity);
+
+#if 0 /* move to after enable_crtc */
+ /* TODO: OPP FMT, ABM. etc. should be done here. */
+ /* or FPGA now. instance 0 only. TODO: move to opp.c */
+
+ inst_offset = reg_offsets[pipe_ctx->tg->inst].fmt;
+
+ pipe_ctx->opp->funcs->opp_program_fmt(
+ pipe_ctx->opp,
+ &stream->bit_depth_params,
+ &stream->clamping);
+#endif
+ /* program otg blank color */
+ color_space = stream->public.output_color_space;
+ color_space_to_black_color(dc, color_space, &black_color);
+ pipe_ctx->tg->funcs->set_blank_color(
+ pipe_ctx->tg,
+ &black_color);
+
+ pipe_ctx->tg->funcs->set_blank(pipe_ctx->tg, true);
+ hwss_wait_for_blank_complete(pipe_ctx->tg);
+
+ /* VTG is within DCHUB command block. DCFCLK is always on */
+ if (false == pipe_ctx->tg->funcs->enable_crtc(pipe_ctx->tg)) {
+ BREAK_TO_DEBUGGER();
+ return DC_ERROR_UNEXPECTED;
+ }
+
+ /* TODO program crtc source select for non-virtual signal*/
+ /* TODO program FMT */
+ /* TODO setup link_enc */
+ /* TODO set stream attributes */
+ /* TODO program audio */
+ /* TODO enable stream if timing changed */
+ /* TODO unblank stream if DP */
+
+ return DC_OK;
+}
+
+static void reset_back_end_for_pipe(
+ struct core_dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ struct validate_context *context)
+{
+ int i;
+ struct dc_bios *bp;
+
+ bp = dc->ctx->dc_bios;
+
+ if (pipe_ctx->stream_enc == NULL) {
+ pipe_ctx->stream = NULL;
+ return;
+ }
+
+ /* TODOFPGA break core_link_disable_stream into 2 functions:
+ * disable_stream and disable_link. disable_link will disable PHYPLL
+ * which is used by otg. Move disable_link after disable_crtc
+ */
+ if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
+ core_link_disable_stream(pipe_ctx);
+
+ /* by upper caller loop, parent pipe: pipe0, will be reset last.
+ * back end share by all pipes and will be disable only when disable
+ * parent pipe.
+ */
+ if (pipe_ctx->top_pipe == NULL) {
+ pipe_ctx->tg->funcs->disable_crtc(pipe_ctx->tg);
+
+ pipe_ctx->tg->funcs->enable_optc_clock(pipe_ctx->tg, false);
+ }
+
+ if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
+ resource_unreference_clock_source(
+ &context->res_ctx, dc->res_pool,
+ &pipe_ctx->clock_source);
+
+ for (i = 0; i < dc->res_pool->pipe_count; i++)
+ if (&dc->current_context->res_ctx.pipe_ctx[i] == pipe_ctx)
+ break;
+
+ if (i == dc->res_pool->pipe_count)
+ return;
+
+ pipe_ctx->stream = NULL;
+}
+
+static void reset_front_end_for_pipe(
+ struct core_dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ struct validate_context *context)
+{
+ struct dcn10_mpc *mpc = TO_DCN10_MPC(dc->res_pool->mpc);
+ struct mpc_tree_cfg *tree_cfg = NULL;
+
+ if (!pipe_ctx->surface)
+ return;
+
+ lock_otg_master_update(dc->ctx, pipe_ctx->tg->inst);
+
+ /* TODO: build stream pipes group id. For now, use stream otg
+ * id as pipe group id
+ */
+ tree_cfg = &context->res_ctx.mpc_tree[pipe_ctx->mpc_idx];
+
+ if (pipe_ctx->top_pipe == NULL)
+ dcn10_delete_mpc_tree(mpc, tree_cfg);
+ else {
+ if (dcn10_remove_dpp(mpc, tree_cfg, pipe_ctx->pipe_idx))
+ pipe_ctx->top_pipe->bottom_pipe = NULL;
+ else {
+ dm_logger_write(dc->ctx->logger, LOG_RESOURCE,
+ "%s: failed to find dpp to be removed!\n",
+ __func__);
+ }
+ }
+
+ pipe_ctx->top_pipe = NULL;
+ pipe_ctx->bottom_pipe = NULL;
+ pipe_ctx->mpc_idx = -1;
+
+ unlock_master_tg_and_wait(dc->ctx, pipe_ctx->tg->inst);
+
+ pipe_ctx->mi->funcs->disable_request(pipe_ctx->mi);
+
+ wait_no_outstanding_request(dc->ctx, pipe_ctx->pipe_idx);
+
+ wait_mpcc_idle(mpc, pipe_ctx->pipe_idx);
+
+ disable_clocks(dc->ctx, pipe_ctx->pipe_idx);
+
+ pipe_ctx->xfm->funcs->transform_reset(pipe_ctx->xfm);
+
+ dm_logger_write(dc->ctx->logger, LOG_DC,
+ "Reset front end for pipe %d\n",
+ pipe_ctx->pipe_idx);
+
+ pipe_ctx->surface = NULL;
+}
+
+static void reset_hw_ctx(struct core_dc *dc,
+ struct validate_context *context,
+ void (*reset)(struct core_dc *dc,
+ struct pipe_ctx *pipe_ctx,
+ struct validate_context *context))
+{
+ int i;
+
+ for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
+ struct pipe_ctx *pipe_ctx_old =
+ &dc->current_context->res_ctx.pipe_ctx[i];
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ if (!pipe_ctx_old->stream)
+ continue;
+
+ if (!pipe_ctx->stream ||
+ pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
+ reset(dc, pipe_ctx_old, dc->current_context);
+ }
+}
+
+static void reset_hw_ctx_wrap(
+ struct core_dc *dc,
+ struct validate_context *context)
+{
+ /* Reset Front End*/
+ reset_hw_ctx(dc, context, reset_front_end_for_pipe);
+ /* Reset Back End*/
+ reset_hw_ctx(dc, context, reset_back_end_for_pipe);
+
+ memcpy(context->res_ctx.mpc_tree,
+ dc->current_context->res_ctx.mpc_tree,
+ sizeof(struct mpc_tree_cfg) * dc->res_pool->pipe_count);
+}
+
+static bool patch_address_for_sbs_tb_stereo(struct pipe_ctx *pipe_ctx,
+ PHYSICAL_ADDRESS_LOC *addr)
+{
+ struct core_surface *surface = pipe_ctx->surface;
+ bool sec_split = pipe_ctx->top_pipe &&
+ pipe_ctx->top_pipe->surface == pipe_ctx->surface;
+ if (sec_split && surface->public.address.type == PLN_ADDR_TYPE_GRPH_STEREO &&
+ (pipe_ctx->stream->public.timing.timing_3d_format ==
+ TIMING_3D_FORMAT_SIDE_BY_SIDE ||
+ pipe_ctx->stream->public.timing.timing_3d_format ==
+ TIMING_3D_FORMAT_TOP_AND_BOTTOM)) {
+ *addr = surface->public.address.grph_stereo.left_addr;
+ surface->public.address.grph_stereo.left_addr =\
+ surface->public.address.grph_stereo.right_addr;
+ return true;
+ }
+ return false;
+}
+
+static void update_plane_addr(const struct core_dc *dc, struct pipe_ctx *pipe_ctx)
+{
+ bool addr_patched = false;
+ PHYSICAL_ADDRESS_LOC addr;
+ struct core_surface *surface = pipe