diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt index 781d34fb2e87..3cc8858ac2fd 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_hdmi-rockchip.txt @@ -26,6 +26,7 @@ Required properties: corresponding to the video input of the controller. The port shall have two endpoints, numbered 0 and 1, connected respectively to the vopb and vopl. - rockchip,grf: Shall reference the GRF to mux vopl/vopb. +- rockchip,phy-table: the parameter table of hdmi phy configuration. Optional properties @@ -68,4 +69,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 a0fe59409923..2c1df71ddd80 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -288,7 +288,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}, @@ -297,9 +297,34 @@ 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].sym_ctr = (u16)config[i * 4 + 1]; + rockchip_phy_config[i].term = (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) { - int ret; + int ret, val, phy_table_size; + u32 *phy_config; struct device_node *np = hdmi->dev->of_node; hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); @@ -343,6 +368,28 @@ static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) hdmi->unsupported_deep_color = of_property_read_bool(np, "unsupported-deep-color"); + 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; }