From ff94633d3423edee23cb95f285f7b11a062a2c28 Mon Sep 17 00:00:00 2001 From: "algea.cao" Date: Fri, 17 Mar 2017 15:56:47 +0800 Subject: [PATCH] drm/rockchip: dw_hdmi-rockchip: get phy config from dts Change-Id: I6903f3b9498be32f9d4936beb2d6d2aa5db43d09 Signed-off-by: algea.cao --- .../display/rockchip/dw_hdmi-rockchip.txt | 6 +++ drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 51 ++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt index e22d70f669a2..5936883df121 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt @@ -20,6 +20,7 @@ Optional properties - clocks, clock-names: phandle to the HDMI CEC clock, name should be "cec", 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. Example: hdmi: hdmi@ff980000 { @@ -46,4 +47,9 @@ hdmi: hdmi@ff980000 { }; }; }; + rockchip,phy-table = <74250000 0x8009 0x0004 0x0272>, + <165000000 0x802b 0x0004 0x0209>, + <297000000 0x8039 0x0005 0x028d>, + <594000000 0x8039 0x0000 0x019d>, + <000000000 0x0000 0x0000 0x0000>; }; diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index 41789871bf4a..65cc55a86478 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -164,7 +164,7 @@ static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { } }; -static const struct dw_hdmi_phy_config rockchip_phy_config[] = { +static struct dw_hdmi_phy_config rockchip_phy_config[] = { /*pixelclk symbol term vlev*/ { 74250000, 0x8009, 0x0004, 0x0272}, { 165000000, 0x802b, 0x0004, 0x0209}, @@ -173,10 +173,35 @@ static const struct dw_hdmi_phy_config rockchip_phy_config[] = { { ~0UL, 0x0000, 0x0000, 0x0000} }; +static int rockchip_hdmi_update_phy_table(struct rockchip_hdmi *hdmi, + u32 *config, + int phy_table_size) +{ + int i; + + if (phy_table_size > ARRAY_SIZE(rockchip_phy_config)) { + dev_err(hdmi->dev, "phy table array number is out of range\n"); + return -E2BIG; + } + + for (i = 0; i < phy_table_size; i++) { + if (config[i * 4] != 0) + rockchip_phy_config[i].mpixelclock = (u64)config[i * 4]; + else + rockchip_phy_config[i].mpixelclock = ~0UL; + rockchip_phy_config[i].term = (u16)config[i * 4 + 1]; + rockchip_phy_config[i].sym_ctr = (u16)config[i * 4 + 2]; + rockchip_phy_config[i].vlev_ctr = (u16)config[i * 4 + 3]; + } + + return 0; +} + static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) { struct device_node *np = hdmi->dev->of_node; - int ret; + int ret, val, phy_table_size; + u32 *phy_config; hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); if (IS_ERR(hdmi->regmap)) { @@ -210,6 +235,28 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) return ret; } + if (of_get_property(np, "rockchip,phy-table", &val)) { + phy_config = kmalloc(val, GFP_KERNEL); + if (!phy_config) { + /* use default table when kmalloc failed. */ + dev_err(hdmi->dev, "kmalloc phy table failed\n"); + + return -ENOMEM; + } + phy_table_size = val / 16; + of_property_read_u32_array(np, "rockchip,phy_table", + phy_config, val / sizeof(u32)); + ret = rockchip_hdmi_update_phy_table(hdmi, phy_config, + phy_table_size); + if (ret) { + kfree(phy_config); + return ret; + } + kfree(phy_config); + } else { + dev_dbg(hdmi->dev, "use default hdmi phy table\n"); + } + return 0; } -- 2.34.1