From: WeiYong Bi Date: Tue, 6 Jun 2017 00:41:21 +0000 (+0800) Subject: drm/rockchip: hdmi: Add support for rk3228 X-Git-Tag: release-20171130_firefly~4^2~381 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=04f59261376a9b95b69e2a92bb5ec4f9412d0c9c;p=firefly-linux-kernel-4.4.55.git drm/rockchip: hdmi: Add support for rk3228 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 --- diff --git a/Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt b/Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt index 531d6463b627..5eb6f94aaaad 100644 --- a/Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt +++ b/Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt @@ -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" diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt index a023c3304e44..2745e5774118 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt @@ -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 { diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index c5b5963f3923..2bf94b87a596 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -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", ®, &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; diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 0bd1201be041..104f8771bd31 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,11 @@ #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); diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 1f6cfe5da644..d5c8d2be0311 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -85,6 +85,7 @@ enum { enum dw_hdmi_devtype { IMX6Q_HDMI, IMX6DL_HDMI, + RK3228_HDMI, RK3288_HDMI, RK3328_HDMI, RK3368_HDMI,