drm/rockchip: hdmi: Add support for rk3228
authorWeiYong Bi <bivvy.bi@rock-chips.com>
Tue, 6 Jun 2017 00:41:21 +0000 (08:41 +0800)
committerWeiYong Bi <bivvy.bi@rock-chips.com>
Tue, 20 Jun 2017 02:33:38 +0000 (10:33 +0800)
RK3228 uses the Synopsys DWC HDMI TX controller and the INNO HDMI PHY to
enabling the integration of a complete HDMI Transmmiter interface.

Change-Id: I90f997968fb2de4165a31216c8aee8213089eab5
Signed-off-by: WeiYong Bi <bivvy.bi@rock-chips.com>
Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt
Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt
drivers/gpu/drm/bridge/dw-hdmi.c
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
include/drm/bridge/dw_hdmi.h

index 531d6463b62759bf42d63fa7eb56d49572e2f1a7..5eb6f94aaaadfd679525e5ad2a45eaaa7c3983d8 100644 (file)
@@ -5,6 +5,7 @@ Required properties:
    * "snps,dw-hdmi-tx"
    * "fsl,imx6q-hdmi"
    * "fsl,imx6dl-hdmi"
+   * "rockchip,rk3228-dw-hdmi"
    * "rockchip,rk3288-dw-hdmi"
    * "rockchip,rk3328-dw-hdmi"
    * "rockchip,rk3399-dw-hdmi"
index a023c3304e44071eaac6f31c3195ce8e5402c737..2745e5774118f9b75f2acff6a8e6944c6495dd26 100644 (file)
@@ -2,7 +2,8 @@ Rockchip specific extensions to the Synopsys Designware HDMI
 ================================
 
 Required properties:
-- compatible: "rockchip,rk3288-dw-hdmi",
+- compatible: "rockchip,rk3228-dw-hdmi",
+             "rockchip,rk3288-dw-hdmi",
              "rockchip,rk3328-dw-hdmi",
              "rockchip,rk3368-dw-hdmi",
              "rockchip,rk3399-dw-hdmi";
@@ -23,6 +24,9 @@ Optional properties
                       phandle to the VPLL clock, name should be "vpll",
                       phandle to the GRF clock, name should be "grf".
 - rockchip,phy-table: the parameter table of hdmi phy configuration.
+- phys: phandle to third party HDMI PHY node
+- phy-names: the string "hdmi_phy" when is found in a node, along with "phys"
+  attribute, provides phandle to HDMI PHY node
 
 Example:
 hdmi: hdmi@ff980000 {
index c5b5963f39239b899bc24eb87664c4d18428713f..2bf94b87a59690ad5e19dd0daf9908b06ba0faff 100644 (file)
@@ -2534,11 +2534,12 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
        phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID);
 
        /*
-        * RK3328 phy_type is DW_HDMI_PHY_DWC_HDMI20_TX_PHY,
+        * RK3228 and RK3328 phy_type is DW_HDMI_PHY_DWC_HDMI20_TX_PHY,
         * but it has a vedor phy.
         */
        if (phy_type == DW_HDMI_PHY_VENDOR_PHY ||
-           hdmi->dev_type == RK3328_HDMI) {
+           hdmi->dev_type == RK3328_HDMI ||
+           hdmi->dev_type == RK3228_HDMI) {
                /* Vendor PHYs require support from the glue layer. */
                if (!hdmi->plat_data->phy_ops || !hdmi->plat_data->phy_name) {
                        dev_err(hdmi->dev,
@@ -2674,6 +2675,9 @@ dw_hdmi_ctrl_write(struct file *file, const char __user *buf,
        u32 reg, val;
        char kbuf[25];
 
+       if (hdmi->dev_type == RK3228_HDMI)
+               return -EFAULT;
+
        if (copy_from_user(kbuf, buf, count))
                return -EFAULT;
        if (sscanf(kbuf, "%x%x", &reg, &val) == -1)
@@ -2702,6 +2706,9 @@ static int dw_hdmi_phy_show(struct seq_file *s, void *v)
        struct dw_hdmi *hdmi = s->private;
        u32 i, total, val;
 
+       if (hdmi->dev_type == RK3228_HDMI)
+               return 0;
+
        seq_puts(s, "\n>>>hdmi_phy reg\n");
        if (hdmi->dev_type != RK3328_HDMI)
                total = 0x28;
index 0bd1201be041f09aaf722e205577a31411b61657..104f8771bd31c571aa939c8f11c5e59daea7b68c 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/rockchip/cpu.h>
 #include <linux/regmap.h>
 #include <linux/pm_runtime.h>
+#include <linux/phy/phy.h>
 
 #include <drm/drm_of.h>
 #include <drm/drmP.h>
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_vop.h"
 
+#define RK3228_GRF_SOC_CON2            0x0408
+#define RK3228_DDC_MASK_EN             ((3 << 13) | (3 << (13 + 16)))
+#define RK3228_GRF_SOC_CON6            0x0418
+#define RK3228_IO_3V_DOMAIN            ((7 << 4) | (7 << (4 + 16)))
+
 #define RK3288_GRF_SOC_CON6            0x025C
 #define RK3288_HDMI_LCDC_SEL           BIT(4)
 #define RK3399_GRF_SOC_CON20           0x6250
@@ -54,6 +60,8 @@ struct rockchip_hdmi {
        struct clk *hdmiphy_clk;
        struct clk *hclk_vio;
        struct clk_hw   hdmiphy_clkhw;
+
+       struct phy *phy;
 };
 
 #define to_rockchip_hdmi(x)    container_of(x, struct rockchip_hdmi, x)
@@ -239,6 +247,11 @@ inno_dw_hdmi_phy_init(struct dw_hdmi *dw_hdmi, void *data,
        const struct inno_phy_config *inno_phy_config = inno_phy_cfg;
        u32 val, i, chipversion = 1;
 
+       if (hdmi->dev_type == RK3228_HDMI) {
+               phy_power_on(hdmi->phy);
+               return 0;
+       }
+
        if (rockchip_get_cpu_version())
                chipversion = 2;
 
@@ -336,6 +349,11 @@ static void inno_dw_hdmi_phy_disable(struct dw_hdmi *dw_hdmi, void *data)
 {
        struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
 
+       if (hdmi->dev_type == RK3228_HDMI) {
+               phy_power_off(hdmi->phy);
+               return;
+       }
+
        /* Power off driver */
        inno_phy_writel(hdmi, 0xb2, 0);
        /* Power off band gap */
@@ -351,6 +369,10 @@ inno_dw_hdmi_phy_read_hpd(struct dw_hdmi *dw_hdmi, void *data)
        enum drm_connector_status status;
 
        status = dw_hdmi_phy_read_hpd(dw_hdmi, data);
+
+       if (hdmi->dev_type == RK3228_HDMI)
+               return status;
+
        if (status == connector_status_connected)
                regmap_write(hdmi->regmap,
                             RK3328_GRF_SOC_CON4,
@@ -992,6 +1014,13 @@ static const struct dw_hdmi_phy_ops inno_dw_hdmi_phy_ops = {
        .write          = inno_dw_hdmi_phy_write,
 };
 
+static const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = {
+       .mode_valid = dw_hdmi_rockchip_mode_valid,
+       .phy_ops    = &inno_dw_hdmi_phy_ops,
+       .phy_name   = "inno_dw_hdmi_phy",
+       .dev_type   = RK3228_HDMI,
+};
+
 static const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = {
        .mode_valid = dw_hdmi_rockchip_mode_valid,
        .mpll_cfg   = rockchip_mpll_cfg,
@@ -1025,6 +1054,9 @@ static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
 };
 
 static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
+       { .compatible = "rockchip,rk3228-dw-hdmi",
+         .data = &rk3228_hdmi_drv_data
+       },
        { .compatible = "rockchip,rk3288-dw-hdmi",
          .data = &rk3288_hdmi_drv_data
        },
@@ -1103,6 +1135,18 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
                if (ret < 0)
                        return ret;
                inno_dw_hdmi_phy_clk_register(hdmi);
+       } else if (hdmi->dev_type == RK3228_HDMI) {
+               hdmi->phy = devm_phy_get(dev, "hdmi_phy");
+               if (IS_ERR(hdmi->phy)) {
+                       ret = PTR_ERR(hdmi->phy);
+                       dev_err(dev, "failed to get phy: %d\n", ret);
+                       return ret;
+               }
+               plat_data->phy_data = hdmi;
+               regmap_write(hdmi->regmap, RK3228_GRF_SOC_CON2,
+                            RK3228_DDC_MASK_EN);
+               regmap_write(hdmi->regmap, RK3228_GRF_SOC_CON6,
+                            RK3228_IO_3V_DOMAIN);
        }
 
        drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
index 1f6cfe5da64468a20317738d7ac18c3c6ca2e7e5..d5c8d2be03115ddfe078b7d1e309533df47f7486 100644 (file)
@@ -85,6 +85,7 @@ enum {
 enum dw_hdmi_devtype {
        IMX6Q_HDMI,
        IMX6DL_HDMI,
+       RK3228_HDMI,
        RK3288_HDMI,
        RK3328_HDMI,
        RK3368_HDMI,