drm/msm/dpu: Configure DP INTF/PHY selector
authorDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Sat, 31 Aug 2024 10:10:44 +0000 (13:10 +0300)
committerDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Sun, 1 Sep 2024 23:53:31 +0000 (02:53 +0300)
Some platforms provides a mechanism for configuring the mapping between
(one or two) DisplayPort intfs and their PHYs.

In particular SC8180X requires this to be configured, since on this
platform there are fewer controllers than PHYs.

The change implements the logic for optionally configuring which PHY
each of the DP INTFs should be connected to and marks the SC8180X DPU to
program 2 entries.

For now the request is simply to program the mapping 1:1, any support
for alternative mappings is left until the use case arrise.

Note that e.g. msm-4.14 unconditionally maps INTF 0 to PHY 0 on all
platforms, so perhaps this is needed in order to get DisplayPort working
on some other platforms as well.

Co-developed-by: Bjorn Andersson <andersson@kernel.org>
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Patchwork: https://patchwork.freedesktop.org/patch/600895/
Link: https://lore.kernel.org/r/20240625-dp-phy-sel-v3-1-c77c7066c454@linaro.org
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h
drivers/gpu/drm/msm/disp/dpu1/dpu_hwio.h
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c

index 6e2ac50b94a4191abe12a4ce96ab4f02f576cf4d..0f40eea7f5e247b5497bac37307c8c5ed639ecea 100644 (file)
@@ -2,6 +2,8 @@
 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
  */
 
+#include <linux/bitfield.h>
+
 #include <drm/drm_managed.h>
 
 #include "dpu_hwio.h"
@@ -231,8 +233,38 @@ static void dpu_hw_intf_audio_select(struct dpu_hw_mdp *mdp)
        DPU_REG_WRITE(c, HDMI_DP_CORE_SELECT, 0x1);
 }
 
+static void dpu_hw_dp_phy_intf_sel(struct dpu_hw_mdp *mdp,
+                                  enum dpu_dp_phy_sel phys[2])
+{
+       struct dpu_hw_blk_reg_map *c = &mdp->hw;
+       unsigned int intf;
+       u32 sel = 0;
+
+       sel |= FIELD_PREP(MDP_DP_PHY_INTF_SEL_INTF0, phys[0]);
+       sel |= FIELD_PREP(MDP_DP_PHY_INTF_SEL_INTF1, phys[1]);
+
+       for (intf = 0; intf < 2; intf++) {
+               switch (phys[intf]) {
+               case DPU_DP_PHY_0:
+                       sel |= FIELD_PREP(MDP_DP_PHY_INTF_SEL_PHY0, intf + 1);
+                       break;
+               case DPU_DP_PHY_1:
+                       sel |= FIELD_PREP(MDP_DP_PHY_INTF_SEL_PHY1, intf + 1);
+                       break;
+               case DPU_DP_PHY_2:
+                       sel |= FIELD_PREP(MDP_DP_PHY_INTF_SEL_PHY2, intf + 1);
+                       break;
+               default:
+                       /* ignore */
+                       break;
+               }
+       }
+
+       DPU_REG_WRITE(c, MDP_DP_PHY_INTF_SEL, sel);
+}
+
 static void _setup_mdp_ops(struct dpu_hw_mdp_ops *ops,
-               unsigned long cap)
+               unsigned long cap, const struct dpu_mdss_version *mdss_rev)
 {
        ops->setup_split_pipe = dpu_hw_setup_split_pipe;
        ops->setup_clk_force_ctrl = dpu_hw_setup_clk_force_ctrl;
@@ -245,6 +277,9 @@ static void _setup_mdp_ops(struct dpu_hw_mdp_ops *ops,
 
        ops->get_safe_status = dpu_hw_get_safe_status;
 
+       if (mdss_rev->core_major_ver >= 5)
+               ops->dp_phy_intf_sel = dpu_hw_dp_phy_intf_sel;
+
        if (cap & BIT(DPU_MDP_AUDIO_SELECT))
                ops->intf_audio_select = dpu_hw_intf_audio_select;
 }
@@ -252,7 +287,7 @@ static void _setup_mdp_ops(struct dpu_hw_mdp_ops *ops,
 struct dpu_hw_mdp *dpu_hw_mdptop_init(struct drm_device *dev,
                                      const struct dpu_mdp_cfg *cfg,
                                      void __iomem *addr,
-                                     const struct dpu_mdss_cfg *m)
+                                     const struct dpu_mdss_version *mdss_rev)
 {
        struct dpu_hw_mdp *mdp;
 
@@ -270,7 +305,7 @@ struct dpu_hw_mdp *dpu_hw_mdptop_init(struct drm_device *dev,
         * Assign ops
         */
        mdp->caps = cfg;
-       _setup_mdp_ops(&mdp->ops, mdp->caps->features);
+       _setup_mdp_ops(&mdp->ops, mdp->caps->features, mdss_rev);
 
        return mdp;
 }
index 5c9a7ede991edc71738ca0fb60973af09d91e3e6..f1ab9fd106e5133dbc7be817fa948e7e290ac85b 100644 (file)
@@ -67,6 +67,13 @@ struct dpu_vsync_source_cfg {
        enum dpu_vsync_source vsync_source;
 };
 
+enum dpu_dp_phy_sel {
+       DPU_DP_PHY_NONE,
+       DPU_DP_PHY_0,
+       DPU_DP_PHY_1,
+       DPU_DP_PHY_2,
+};
+
 /**
  * struct dpu_hw_mdp_ops - interface to the MDP TOP Hw driver functions
  * Assumption is these functions will be called after clocks are enabled.
@@ -125,6 +132,13 @@ struct dpu_hw_mdp_ops {
        void (*get_safe_status)(struct dpu_hw_mdp *mdp,
                        struct dpu_danger_safe_status *status);
 
+       /**
+        * dp_phy_intf_sel - configure intf to phy mapping
+        * @mdp: mdp top context driver
+        * @phys: list of phys the DP interfaces should be connected to. 0 disables the INTF.
+        */
+       void (*dp_phy_intf_sel)(struct dpu_hw_mdp *mdp, enum dpu_dp_phy_sel phys[2]);
+
        /**
         * intf_audio_select - select the external interface for audio
         * @mdp: mdp top context driver
@@ -148,12 +162,12 @@ struct dpu_hw_mdp {
  * @dev:  Corresponding device for devres management
  * @cfg:  MDP TOP configuration from catalog
  * @addr: Mapped register io address of MDP
- * @m:    Pointer to mdss catalog data
+ * @mdss_rev: dpu core's major and minor versions
  */
 struct dpu_hw_mdp *dpu_hw_mdptop_init(struct drm_device *dev,
                                      const struct dpu_mdp_cfg *cfg,
                                      void __iomem *addr,
-                                     const struct dpu_mdss_cfg *m);
+                                     const struct dpu_mdss_version *mdss_rev);
 
 void dpu_hw_mdp_destroy(struct dpu_hw_mdp *mdp);
 
index 5acd5683d25a4021950a80d341d732ac6d7fc856..054fe097ebf802dd98eece459f78da2574eb5904 100644 (file)
 #define MDP_WD_TIMER_4_LOAD_VALUE       0x448
 #define DCE_SEL                         0x450
 
+#define MDP_DP_PHY_INTF_SEL             0x460
+#define MDP_DP_PHY_INTF_SEL_INTF0              GENMASK(2, 0)
+#define MDP_DP_PHY_INTF_SEL_INTF1              GENMASK(5, 3)
+#define MDP_DP_PHY_INTF_SEL_PHY0               GENMASK(8, 6)
+#define MDP_DP_PHY_INTF_SEL_PHY1               GENMASK(11, 9)
+#define MDP_DP_PHY_INTF_SEL_PHY2               GENMASK(14, 12)
+
 #define MDP_PERIPH_TOP0                        MDP_WD_TIMER_0_CTL
 #define MDP_PERIPH_TOP0_END            CLK_CTRL3
 
index d1e2143110f2bb989442c4829321e53310104ddc..9bcae53c4f458cd8e400f0e851b791c0f4165085 100644 (file)
@@ -1146,7 +1146,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
        dpu_kms->hw_mdp = dpu_hw_mdptop_init(dev,
                                             dpu_kms->catalog->mdp,
                                             dpu_kms->mmio,
-                                            dpu_kms->catalog);
+                                            dpu_kms->catalog->mdss_ver);
        if (IS_ERR(dpu_kms->hw_mdp)) {
                rc = PTR_ERR(dpu_kms->hw_mdp);
                DPU_ERROR("failed to get hw_mdp: %d\n", rc);
@@ -1181,6 +1181,16 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
                goto err_pm_put;
        }
 
+       /*
+        * We need to program DP <-> PHY relationship only for SC8180X since it
+        * has fewer DP controllers than DP PHYs.
+        * If any other platform requires the same kind of programming, or if
+        * the INTF <->DP relationship isn't static anymore, this needs to be
+        * configured through the DT.
+        */
+       if (of_device_is_compatible(dpu_kms->pdev->dev.of_node, "qcom,sc8180x-dpu"))
+               dpu_kms->hw_mdp->ops.dp_phy_intf_sel(dpu_kms->hw_mdp, (unsigned int[]){ 1, 2, });
+
        dpu_kms->hw_intr = dpu_hw_intr_init(dev, dpu_kms->mmio, dpu_kms->catalog);
        if (IS_ERR(dpu_kms->hw_intr)) {
                rc = PTR_ERR(dpu_kms->hw_intr);