From: Andy Yan <andy....@rock-chips.com>

The HSYNC/VSYNC polarity of rk3036 HDMI are controlled by GRF.
Without the polarity configuration in GRF, it can be observed
from the HDMI protocol analyzer that the H/V front/back timing
output by RK3036 HDMI are currently not in line with the specifications.

Signed-off-by: Andy Yan <andy....@rock-chips.com>

---

Changes in v2:
- First included in this series

 drivers/gpu/drm/rockchip/inno_hdmi.c | 36 +++++++++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c 
b/drivers/gpu/drm/rockchip/inno_hdmi.c
index e891d42dd08a4..db4b4038e51d5 100644
--- a/drivers/gpu/drm/rockchip/inno_hdmi.c
+++ b/drivers/gpu/drm/rockchip/inno_hdmi.c
@@ -10,10 +10,12 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/hdmi.h>
+#include <linux/mfd/syscon.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
@@ -29,8 +31,19 @@
 
 #include "inno_hdmi.h"
 
+#define HIWORD_UPDATE(val, mask)       ((val) | (mask) << 16)
+
 #define INNO_HDMI_MIN_TMDS_CLOCK  25000000U
 
+#define RK3036_GRF_SOC_CON2    0x148
+#define RK3036_HDMI_PHSYNC     BIT(4)
+#define RK3036_HDMI_PVSYNC     BIT(5)
+
+enum inno_hdmi_dev_type {
+       RK3036_HDMI,
+       RK3128_HDMI,
+};
+
 struct inno_hdmi_phy_config {
        unsigned long pixelclock;
        u8 pre_emphasis;
@@ -38,6 +51,7 @@ struct inno_hdmi_phy_config {
 };
 
 struct inno_hdmi_variant {
+       enum inno_hdmi_dev_type dev_type;
        struct inno_hdmi_phy_config *phy_configs;
        struct inno_hdmi_phy_config *default_phy_config;
 };
@@ -58,6 +72,7 @@ struct inno_hdmi {
        struct clk *pclk;
        struct clk *refclk;
        void __iomem *regs;
+       struct regmap *grf;
 
        struct drm_connector    connector;
        struct rockchip_encoder encoder;
@@ -374,7 +389,15 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi 
*hdmi)
 static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
                                         struct drm_display_mode *mode)
 {
-       int value;
+       int value, psync;
+
+       if (hdmi->variant->dev_type == RK3036_HDMI) {
+               psync = mode->flags & DRM_MODE_FLAG_PHSYNC ? RK3036_HDMI_PHSYNC 
: 0;
+               value = HIWORD_UPDATE(psync, RK3036_HDMI_PHSYNC);
+               psync = mode->flags & DRM_MODE_FLAG_PVSYNC ? RK3036_HDMI_PVSYNC 
: 0;
+               value |= HIWORD_UPDATE(psync, RK3036_HDMI_PVSYNC);
+               regmap_write(hdmi->grf, RK3036_GRF_SOC_CON2, value);
+       }
 
        /* Set detail external video timing polarity and interlace mode */
        value = v_EXTERANL_VIDEO(1);
@@ -904,6 +927,15 @@ static int inno_hdmi_bind(struct device *dev, struct 
device *master,
                goto err_disable_pclk;
        }
 
+       if (hdmi->variant->dev_type == RK3036_HDMI) {
+               hdmi->grf = syscon_regmap_lookup_by_phandle(dev->of_node, 
"rockchip,grf");
+               if (IS_ERR(hdmi->grf)) {
+                       ret = dev_err_probe(dev, PTR_ERR(hdmi->grf),
+                                           "Unable to get rockchip,grf\n");
+                       goto err_disable_clk;
+               }
+       }
+
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                ret = irq;
@@ -988,11 +1020,13 @@ static void inno_hdmi_remove(struct platform_device 
*pdev)
 }
 
 static const struct inno_hdmi_variant rk3036_inno_hdmi_variant = {
+       .dev_type = RK3036_HDMI,
        .phy_configs = rk3036_hdmi_phy_configs,
        .default_phy_config = &rk3036_hdmi_phy_configs[1],
 };
 
 static const struct inno_hdmi_variant rk3128_inno_hdmi_variant = {
+       .dev_type = RK3128_HDMI,
        .phy_configs = rk3128_hdmi_phy_configs,
        .default_phy_config = &rk3128_hdmi_phy_configs[1],
 };
-- 
2.43.0

Reply via email to