HW Blocks:

        +--------+  +-----+  +------+
        |  OPTC  |  | HDA |  | HUBP |
        +--------+  +-----+  +------+
            |          |        |
            |          |        |
    HPO ====|==========|========|====
     |      |          v        |
     |      |       +-----+     |
     |      |       | APG |     |
     |      |       +-----+     |
     |      |          |        |
     |      v          v        v
     |     +---------------------+
     |     |  HPO Stream Encoder |
     |     +---------------------+
     |                 |
     |                 v
     |      +--------------------+
     |      |  HPO Link Encoder  |
     |      +--------------------+
     |                 |
     v  ===============|=============
                       v
              +------------------+
              |  DIO Output Mux  |
              +------------------+
                       |
                       v
                    +-----+
                    | PHY |
                    +-----+
                       | PHYD32CLK[0]
                       v
                    +------+
                    | DCCG |
                    +------+
                       |
                       v
                   SYMCLK32

Signed-off-by: Fangzhi Zuo <jerry....@amd.com>
---
 .../gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c | 162 ++++++++++++++++++
 .../gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h |  18 ++
 drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h  |  23 +++
 .../amd/display/dc/inc/hw/timing_generator.h  |   3 +
 4 files changed, 206 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c 
b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c
index 696c9307715d..9896adf67425 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c
@@ -42,6 +42,155 @@
 #define DC_LOGGER \
        dccg->ctx->logger
 
+void dccg31_set_dpstreamclk(
+               struct dccg *dccg,
+               enum hdmistreamclk_source src,
+               int otg_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       /* enabled to select one of the DTBCLKs for pipe */
+       switch (otg_inst) {
+       case 0:
+               REG_UPDATE(DPSTREAMCLK_CNTL,
+                               DPSTREAMCLK_PIPE0_EN, (src == REFCLK) ? 0 : 1);
+               break;
+       case 1:
+               REG_UPDATE(DPSTREAMCLK_CNTL,
+                               DPSTREAMCLK_PIPE1_EN, (src == REFCLK) ? 0 : 1);
+               break;
+       case 2:
+               REG_UPDATE(DPSTREAMCLK_CNTL,
+                               DPSTREAMCLK_PIPE2_EN, (src == REFCLK) ? 0 : 1);
+               break;
+       case 3:
+               REG_UPDATE(DPSTREAMCLK_CNTL,
+                               DPSTREAMCLK_PIPE3_EN, (src == REFCLK) ? 0 : 1);
+               break;
+       default:
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+}
+
+void dccg31_enable_symclk32_se(
+               struct dccg *dccg,
+               int hpo_se_inst,
+               enum phyd32clk_clock_source phyd32clk)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       /* select one of the PHYD32CLKs as the source for symclk32_se */
+       switch (hpo_se_inst) {
+       case 0:
+               REG_UPDATE_2(SYMCLK32_SE_CNTL,
+                               SYMCLK32_SE0_SRC_SEL, phyd32clk,
+                               SYMCLK32_SE0_EN, 1);
+               break;
+       case 1:
+               REG_UPDATE_2(SYMCLK32_SE_CNTL,
+                               SYMCLK32_SE1_SRC_SEL, phyd32clk,
+                               SYMCLK32_SE1_EN, 1);
+               break;
+       case 2:
+               REG_UPDATE_2(SYMCLK32_SE_CNTL,
+                               SYMCLK32_SE2_SRC_SEL, phyd32clk,
+                               SYMCLK32_SE2_EN, 1);
+               break;
+       case 3:
+               REG_UPDATE_2(SYMCLK32_SE_CNTL,
+                               SYMCLK32_SE3_SRC_SEL, phyd32clk,
+                               SYMCLK32_SE3_EN, 1);
+               break;
+       default:
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+}
+
+void dccg31_disable_symclk32_se(
+               struct dccg *dccg,
+               int hpo_se_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       /* set refclk as the source for symclk32_se */
+       switch (hpo_se_inst) {
+       case 0:
+               REG_UPDATE_2(SYMCLK32_SE_CNTL,
+                               SYMCLK32_SE0_SRC_SEL, 0,
+                               SYMCLK32_SE0_EN, 0);
+               break;
+       case 1:
+               REG_UPDATE_2(SYMCLK32_SE_CNTL,
+                               SYMCLK32_SE1_SRC_SEL, 0,
+                               SYMCLK32_SE1_EN, 0);
+               break;
+       case 2:
+               REG_UPDATE_2(SYMCLK32_SE_CNTL,
+                               SYMCLK32_SE2_SRC_SEL, 0,
+                               SYMCLK32_SE2_EN, 0);
+               break;
+       case 3:
+               REG_UPDATE_2(SYMCLK32_SE_CNTL,
+                               SYMCLK32_SE3_SRC_SEL, 0,
+                               SYMCLK32_SE3_EN, 0);
+               break;
+       default:
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+}
+
+void dccg31_enable_symclk32_le(
+               struct dccg *dccg,
+               int hpo_le_inst,
+               enum phyd32clk_clock_source phyd32clk)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       /* select one of the PHYD32CLKs as the source for symclk32_le */
+       switch (hpo_le_inst) {
+       case 0:
+               REG_UPDATE_2(SYMCLK32_LE_CNTL,
+                               SYMCLK32_LE0_SRC_SEL, phyd32clk,
+                               SYMCLK32_LE0_EN, 1);
+               break;
+       case 1:
+               REG_UPDATE_2(SYMCLK32_LE_CNTL,
+                               SYMCLK32_LE1_SRC_SEL, phyd32clk,
+                               SYMCLK32_LE1_EN, 1);
+               break;
+       default:
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+}
+
+void dccg31_disable_symclk32_le(
+               struct dccg *dccg,
+               int hpo_le_inst)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       /* set refclk as the source for symclk32_le */
+       switch (hpo_le_inst) {
+       case 0:
+               REG_UPDATE_2(SYMCLK32_LE_CNTL,
+                               SYMCLK32_LE0_SRC_SEL, 0,
+                               SYMCLK32_LE0_EN, 0);
+               break;
+       case 1:
+               REG_UPDATE_2(SYMCLK32_LE_CNTL,
+                               SYMCLK32_LE1_SRC_SEL, 0,
+                               SYMCLK32_LE1_EN, 0);
+               break;
+       default:
+               BREAK_TO_DEBUGGER();
+               return;
+       }
+}
+
 void dccg31_set_physymclk(
                struct dccg *dccg,
                int phy_inst,
@@ -241,12 +390,25 @@ static void dccg31_set_dispclk_change_mode(
 
 void dccg31_init(struct dccg *dccg)
 {
+       /* Set HPO stream encoder to use refclk to avoid case where PHY is
+        * disabled and SYMCLK32 for HPO SE is sourced from PHYD32CLK which
+        * will cause DCN to hang.
+        */
+       dccg31_disable_symclk32_se(dccg, 0);
+       dccg31_disable_symclk32_se(dccg, 1);
+       dccg31_disable_symclk32_se(dccg, 2);
+       dccg31_disable_symclk32_se(dccg, 3);
 }
 
 static const struct dccg_funcs dccg31_funcs = {
        .update_dpp_dto = dccg2_update_dpp_dto,
        .get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
        .dccg_init = dccg31_init,
+       .set_dpstreamclk = dccg31_set_dpstreamclk,
+       .enable_symclk32_se = dccg31_enable_symclk32_se,
+       .disable_symclk32_se = dccg31_disable_symclk32_se,
+       .enable_symclk32_le = dccg31_enable_symclk32_le,
+       .disable_symclk32_le = dccg31_disable_symclk32_le,
        .set_physymclk = dccg31_set_physymclk,
        .set_dtbclk_dto = dccg31_set_dtbclk_dto,
        .set_audio_dtbclk_dto = dccg31_set_audio_dtbclk_dto,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h 
b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h
index 706ad80ba873..1e5aabcb7799 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h
@@ -130,6 +130,24 @@ struct dccg *dccg31_create(
 
 void dccg31_init(struct dccg *dccg);
 
+void dccg31_enable_symclk32_se(
+               struct dccg *dccg,
+               int hpo_se_inst,
+               enum phyd32clk_clock_source phyd32clk);
+
+void dccg31_disable_symclk32_se(
+               struct dccg *dccg,
+               int hpo_se_inst);
+
+void dccg31_enable_symclk32_le(
+               struct dccg *dccg,
+               int hpo_le_inst,
+               enum phyd32clk_clock_source phyd32clk);
+
+void dccg31_disable_symclk32_le(
+               struct dccg *dccg,
+               int hpo_le_inst);
+
 void dccg31_set_physymclk(
                struct dccg *dccg,
                int phy_inst,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h 
b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
index 0afa2364a986..09237d5819f4 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
@@ -79,7 +79,30 @@ struct dccg_funcs {
        void (*otg_drop_pixel)(struct dccg *dccg,
                        uint32_t otg_inst);
        void (*dccg_init)(struct dccg *dccg);
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       void (*set_dpstreamclk)(
+                       struct dccg *dccg,
+                       enum hdmistreamclk_source src,
+                       int otg_inst);
+
+       void (*enable_symclk32_se)(
+                       struct dccg *dccg,
+                       int hpo_se_inst,
+                       enum phyd32clk_clock_source phyd32clk);
+
+       void (*disable_symclk32_se)(
+                       struct dccg *dccg,
+                       int hpo_se_inst);
+
+       void (*enable_symclk32_le)(
+                       struct dccg *dccg,
+                       int hpo_le_inst,
+                       enum phyd32clk_clock_source phyd32clk);
 
+       void (*disable_symclk32_le)(
+                       struct dccg *dccg,
+                       int hpo_le_inst);
+#endif
        void (*set_physymclk)(
                        struct dccg *dccg,
                        int phy_inst,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h 
b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
index 03f47f23fb65..7390baf916b5 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
@@ -100,6 +100,9 @@ enum crc_selection {
 
 enum otg_out_mux_dest {
        OUT_MUX_DIO = 0,
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+       OUT_MUX_HPO_DP = 2,
+#endif
 };
 
 enum h_timing_div_mode {
-- 
2.25.1

Reply via email to