Qualcomm Eliza SoC with DPU v12.4 comes with HDMI on INTF_11 with
additional INTR registers.  The device clocks look different comparing
to last variant of HDMI from MSM8998.

Signed-off-by: Krzysztof Kozlowski <[email protected]>
---
 .../gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h |  8 +++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c  | 15 +++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h  |  3 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h        |  3 +
 drivers/gpu/drm/msm/hdmi/hdmi.c                    | 32 +++++++++
 drivers/gpu/drm/msm/hdmi/hdmi.h                    |  4 ++
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c             | 75 +++++++++++++++++++---
 drivers/gpu/drm/msm/msm_drv.h                      |  5 ++
 8 files changed, 136 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h 
b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h
index b93d32888972..c95cf4e38c12 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_12_4_eliza.h
@@ -294,6 +294,14 @@ static const struct dpu_intf_cfg eliza_intf[] = {
                .prog_fetch_lines_worst_case = 24,
                .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30),
                .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31),
+       }, {
+               .name = "intf_11", .id = INTF_11,
+               .base = 0x3f000, .len = 0x4bc,
+               .type = INTF_HDMI,
+               .controller_id = MSM_HDMI_CONTROLLER_0,
+               .prog_fetch_lines_worst_case = 24,
+               .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 14),
+               .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 15),
        }
 };
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
index 5b7cd5241f45..f6d1f944f4ba 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c
@@ -206,6 +206,21 @@ static const struct dpu_intr_reg dpu_intr_set_7xxx[] = {
                MDP_INTF_REV_7xxx_INTR_EN(8),
                MDP_INTF_REV_7xxx_INTR_STATUS(8)
        },
+       [MDP_INTF9_INTR] = {
+               MDP_INTF_REV_7xxx_INTR_CLEAR(9),
+               MDP_INTF_REV_7xxx_INTR_EN(9),
+               MDP_INTF_REV_7xxx_INTR_STATUS(9)
+       },
+       [MDP_INTF10_INTR] = {
+               MDP_INTF_REV_7xxx_INTR_CLEAR(10),
+               MDP_INTF_REV_7xxx_INTR_EN(10),
+               MDP_INTF_REV_7xxx_INTR_STATUS(10)
+       },
+       [MDP_INTF11_INTR] = {
+               MDP_INTF_REV_7xxx_INTR_CLEAR(11),
+               MDP_INTF_REV_7xxx_INTR_EN(11),
+               MDP_INTF_REV_7xxx_INTR_STATUS(11)
+       },
 };
 
 /*
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
index 142358a105c5..231809607be1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
@@ -27,6 +27,9 @@ enum dpu_hw_intr_reg {
        MDP_INTF6_INTR,
        MDP_INTF7_INTR,
        MDP_INTF8_INTR,
+       MDP_INTF9_INTR,
+       MDP_INTF10_INTR,
+       MDP_INTF11_INTR,
        MDP_INTF1_TEAR_INTR,
        MDP_INTF2_TEAR_INTR,
        MDP_AD4_0_INTR,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h 
b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
index 0e65bf5ddc4a..bdcc0caa4e4f 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h
@@ -226,6 +226,9 @@ enum dpu_intf {
        INTF_6,
        INTF_7,
        INTF_8,
+       INTF_9,
+       INTF_10,
+       INTF_11,
        INTF_MAX
 };
 
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index c46f30063f14..b769780cd5dd 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -234,6 +234,16 @@ static const struct hdmi_platform_config 
hdmi_tx_8974_config = {
        .pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names_8x74),
 };
 
+static const char * const pwr_reg_names_eliza[] = {"core-vdda", "core-vcc", 
"vddio"};
+static const char * const pwr_clk_names_eliza[] = {"iface", "core"};
+
+static const struct hdmi_platform_config hdmi_tx_eliza_config = {
+       .pwr_reg_names = pwr_reg_names_eliza,
+       .pwr_reg_cnt = ARRAY_SIZE(pwr_reg_names_eliza),
+       .pwr_clk_names = pwr_clk_names_eliza,
+       .pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names_eliza),
+};
+
 static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
 {
        struct msm_drm_private *priv = dev_get_drvdata(master);
@@ -360,6 +370,27 @@ static int msm_hdmi_dev_probe(struct platform_device *pdev)
                goto err_put_bridge;
        }
 
+       hdmi->phy_iface_clk = devm_clk_get_optional(dev, "phy_iface");
+       if (IS_ERR(hdmi->phy_iface_clk)) {
+               ret = dev_err_probe(dev, PTR_ERR(hdmi->phy_iface_clk),
+                                   "failed to get phy iface clock\n");
+               goto err_put_bridge;
+       }
+
+       hdmi->pixel_src_clk = devm_clk_get_optional(dev, "pixel_src");
+       if (IS_ERR(hdmi->pixel_src_clk)) {
+               ret = dev_err_probe(dev, PTR_ERR(hdmi->pixel_src_clk),
+                                   "failed to get pixel src clock\n");
+               goto err_put_bridge;
+       }
+
+       hdmi->pll_clk = devm_clk_get_optional(dev, "pll");
+       if (IS_ERR(hdmi->pll_clk)) {
+               ret = dev_err_probe(dev, PTR_ERR(hdmi->pll_clk),
+                                   "failed to get pll clock\n");
+               goto err_put_bridge;
+       }
+
        hdmi->hpd_gpiod = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN);
        /* This will catch e.g. -EPROBE_DEFER */
        if (IS_ERR(hdmi->hpd_gpiod)) {
@@ -458,6 +489,7 @@ static int msm_hdmi_runtime_resume(struct device *dev)
 static DEFINE_RUNTIME_DEV_PM_OPS(msm_hdmi_pm_ops, msm_hdmi_runtime_suspend, 
msm_hdmi_runtime_resume, NULL);
 
 static const struct of_device_id msm_hdmi_dt_match[] = {
+       { .compatible = "qcom,eliza-hdmi-tx", .data = &hdmi_tx_eliza_config },
        { .compatible = "qcom,hdmi-tx-8998", .data = &hdmi_tx_8974_config },
        { .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8974_config },
        { .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8974_config },
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 306b988bca72..2fa9bec455b4 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -52,6 +52,9 @@ struct hdmi {
        struct regulator_bulk_data *pwr_regs;
        struct clk_bulk_data *pwr_clks;
        struct clk *extp_clk;
+       struct clk *phy_iface_clk;
+       struct clk *pixel_src_clk;
+       struct clk *pll_clk;
 
        struct gpio_desc *hpd_gpiod;
 
@@ -171,6 +174,7 @@ struct hdmi_phy {
        struct platform_device *pdev;
        void __iomem *mmio;
        struct hdmi_phy_cfg *cfg;
+       void *pll;
        const struct hdmi_phy_funcs *funcs;
        struct regulator_bulk_data *regs;
        struct clk **clks;
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c 
b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 621083a97b37..c6a75f653915 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -14,6 +14,18 @@
 #include "msm_kms.h"
 #include "hdmi.h"
 
+static void msm_hdmi_clk_reparent(struct hdmi *hdmi)
+{
+       int ret;
+
+       if (hdmi->pixel_src_clk && hdmi->pll_clk) {
+               ret = clk_set_parent(hdmi->pixel_src_clk, hdmi->pll_clk);
+               if (ret)
+                       DRM_DEV_ERROR(hdmi->dev->dev, "failed to set reparent 
pixel src clock rate: %d\n",
+                                     ret);
+       }
+}
+
 static void msm_hdmi_power_on(struct drm_bridge *bridge)
 {
        struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
@@ -29,16 +41,34 @@ static void msm_hdmi_clk_prepare(struct drm_bridge *bridge)
        struct hdmi *hdmi = hdmi_bridge->hdmi;
        int ret;
 
+       msm_hdmi_clk_reparent(hdmi);
        if (hdmi->extp_clk) {
+               /*
+                * Set rate to hdmi->pixclock: PCLK_CLK_SRC and PCLK_CLK
+                * Set rate to hdmi->pixclock/2: INTF_CLK and PCLK_DIV_CLK_SRC
+                * Set rate to hdmi->pixclock: HDMI PHY PLL
+                */
                DBG("pixclock: %lu", hdmi->pixclock);
 
                ret = dev_pm_opp_set_rate(&hdmi->pdev->dev, hdmi->pixclock);
                if (ret)
                        DRM_DEV_ERROR(dev->dev, "failed to set OPP rate: %d\n", 
ret);
 
+               ret = clk_set_rate(hdmi->pixel_src_clk, hdmi->pixclock);
+               if (ret)
+                       DRM_DEV_ERROR(dev->dev, "failed to set pixel src clk 
rate: %d\n", ret);
+
+               ret = clk_set_rate(hdmi->phy_iface_clk, hdmi->pixclock / 2);
+               if (ret)
+                       DRM_DEV_ERROR(dev->dev, "failed to set pixel iface clk 
rate: %d\n", ret);
+
                ret = clk_prepare_enable(hdmi->extp_clk);
                if (ret)
                        DRM_DEV_ERROR(dev->dev, "failed to enable extp clk: 
%d\n", ret);
+
+               ret = clk_prepare_enable(hdmi->phy_iface_clk);
+               if (ret)
+                       DRM_DEV_ERROR(dev->dev, "failed to enable phy iface 
clk: %d\n", ret);
        }
 }
 
@@ -61,6 +91,7 @@ static void msm_hdmi_clk_unprepare(struct drm_bridge *bridge)
        struct hdmi *hdmi = hdmi_bridge->hdmi;
 
        if (hdmi->extp_clk) {
+               clk_disable_unprepare(hdmi->phy_iface_clk);
                clk_disable_unprepare(hdmi->extp_clk);
                dev_pm_opp_set_rate(&hdmi->pdev->dev, 0);
        }
@@ -443,21 +474,47 @@ static enum drm_mode_status 
msm_hdmi_bridge_tmds_char_rate_valid(const struct dr
         * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
         * instead):
         */
-       if (kms->funcs->round_pixclk)
+       if (kms->funcs->round_pixclk) {
                actual = kms->funcs->round_pixclk(kms,
                                                  tmds_rate,
                                                  hdmi_bridge->hdmi->encoder);
-       else if (hdmi->extp_clk)
-               actual = clk_round_rate(hdmi->extp_clk, tmds_rate);
-       else
-               actual = tmds_rate;
+               DBG("requested=%lld, actual=%ld", tmds_rate, actual);
 
-       DBG("requested=%lld, actual=%ld", tmds_rate, actual);
+               if (actual != tmds_rate)
+                       return MODE_CLOCK_RANGE;
+               return MODE_OK;
+       } else if (!dev_pm_opp_get_opp_count(&hdmi->pdev->dev)) {
+               if (hdmi->extp_clk)
+                       actual = clk_round_rate(hdmi->extp_clk, tmds_rate);
+               else
+                       actual = tmds_rate;
 
-       if (actual != tmds_rate)
-               return MODE_CLOCK_RANGE;
+               if (actual != tmds_rate)
+                       return MODE_CLOCK_RANGE;
+               return MODE_OK;
+       } else {
+               struct dev_pm_opp *opp;
+               unsigned long pclk_rate = tmds_rate;
 
-       return 0;
+               if (mode->clock > 600000)
+                       return MODE_CLOCK_HIGH;
+
+               opp = dev_pm_opp_find_freq_ceil(&hdmi->pdev->dev, &pclk_rate);
+               if (!IS_ERR(opp)) {
+                       dev_pm_opp_put(opp);
+               } else if (PTR_ERR(opp) == -ERANGE) {
+                       /*
+                        * An empty table is created by 
devm_pm_opp_set_clkname() even
+                        * if there is none. Thus find_freq_ceil will still 
return
+                        * -ERANGE in such case.
+                        */
+                       return MODE_CLOCK_RANGE;
+               } else {
+                       return MODE_ERROR;
+               }
+
+               return MODE_OK;
+       }
 }
 
 static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index eb4bbae8557b..e63c63ae7d6f 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -67,6 +67,11 @@ enum msm_dsi_controller {
        MSM_DSI_CONTROLLER_COUNT,
 };
 
+enum msm_hdmi_controller {
+       MSM_HDMI_CONTROLLER_0,
+       MSM_HDMI_CONTROLLER_COUNT,
+};
+
 #define MSM_GPU_MAX_RINGS 4
 
 struct msm_drm_private {

-- 
2.53.0

Reply via email to