| From 40aac568e42ffb308a0d9aaf6a2694d9b60ccb0b Mon Sep 17 00:00:00 2001 |
| From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> |
| Date: Tue, 17 Jan 2017 10:29:06 +0200 |
| Subject: [PATCH 251/255] drm: bridge: dw-hdmi: Detect PHY type at runtime |
| |
| Detect the PHY type and use it to handle the PHY type-specific SVSRET |
| signal. |
| |
| Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> |
| Signed-off-by: Archit Taneja <architt@codeaurora.org> |
| Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-17-laurent.pinchart+renesas@ideasonboard.com |
| (cherry picked from commit faba6c3cff177689aec132291b1cf537831d9a2e) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/gpu/drm/bridge/dw-hdmi.c | 68 +++++++++++++++++++++++++++++++++++++-- |
| include/drm/bridge/dw_hdmi.h | 10 +++++ |
| 2 files changed, 75 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/gpu/drm/bridge/dw-hdmi.c |
| +++ b/drivers/gpu/drm/bridge/dw-hdmi.c |
| @@ -113,6 +113,12 @@ struct dw_hdmi_i2c { |
| bool is_regaddr; |
| }; |
| |
| +struct dw_hdmi_phy_data { |
| + enum dw_hdmi_phy_type type; |
| + const char *name; |
| + bool has_svsret; |
| +}; |
| + |
| struct dw_hdmi { |
| struct drm_connector connector; |
| struct drm_bridge bridge; |
| @@ -134,7 +140,9 @@ struct dw_hdmi { |
| u8 edid[HDMI_EDID_LEN]; |
| bool cable_plugin; |
| |
| + const struct dw_hdmi_phy_data *phy; |
| bool phy_enabled; |
| + |
| struct drm_display_mode previous_mode; |
| |
| struct i2c_adapter *ddc; |
| @@ -1015,7 +1023,8 @@ static int hdmi_phy_configure(struct dw_ |
| dw_hdmi_phy_gen2_txpwron(hdmi, 1); |
| dw_hdmi_phy_gen2_pddq(hdmi, 0); |
| |
| - if (hdmi->dev_type == RK3288_HDMI) |
| + /* The DWC MHL and HDMI 2.0 PHYs need the SVSRET signal to be set. */ |
| + if (hdmi->phy->has_svsret) |
| dw_hdmi_phy_enable_svsret(hdmi, 1); |
| |
| /*Wait for PHY PLL lock */ |
| @@ -1840,6 +1849,54 @@ static irqreturn_t dw_hdmi_irq(int irq, |
| return IRQ_HANDLED; |
| } |
| |
| +static const struct dw_hdmi_phy_data dw_hdmi_phys[] = { |
| + { |
| + .type = DW_HDMI_PHY_DWC_HDMI_TX_PHY, |
| + .name = "DWC HDMI TX PHY", |
| + }, { |
| + .type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC, |
| + .name = "DWC MHL PHY + HEAC PHY", |
| + .has_svsret = true, |
| + }, { |
| + .type = DW_HDMI_PHY_DWC_MHL_PHY, |
| + .name = "DWC MHL PHY", |
| + .has_svsret = true, |
| + }, { |
| + .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC, |
| + .name = "DWC HDMI 3D TX PHY + HEAC PHY", |
| + }, { |
| + .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY, |
| + .name = "DWC HDMI 3D TX PHY", |
| + }, { |
| + .type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY, |
| + .name = "DWC HDMI 2.0 TX PHY", |
| + .has_svsret = true, |
| + } |
| +}; |
| + |
| +static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi) |
| +{ |
| + unsigned int i; |
| + u8 phy_type; |
| + |
| + phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID); |
| + |
| + for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) { |
| + if (dw_hdmi_phys[i].type == phy_type) { |
| + hdmi->phy = &dw_hdmi_phys[i]; |
| + return 0; |
| + } |
| + } |
| + |
| + if (phy_type == DW_HDMI_PHY_VENDOR_PHY) |
| + dev_err(hdmi->dev, "Unsupported vendor HDMI PHY\n"); |
| + else |
| + dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n", |
| + phy_type); |
| + |
| + return -ENODEV; |
| +} |
| + |
| static struct dw_hdmi * |
| __dw_hdmi_probe(struct platform_device *pdev, |
| const struct dw_hdmi_plat_data *plat_data) |
| @@ -1950,9 +2007,14 @@ __dw_hdmi_probe(struct platform_device * |
| goto err_iahb; |
| } |
| |
| - dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP\n", |
| + ret = dw_hdmi_detect_phy(hdmi); |
| + if (ret < 0) |
| + goto err_iahb; |
| + |
| + dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n", |
| hdmi->version >> 12, hdmi->version & 0xfff, |
| - prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without"); |
| + prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without", |
| + hdmi->phy->name); |
| |
| initialize_hdmi_ih_mutes(hdmi); |
| |
| --- a/include/drm/bridge/dw_hdmi.h |
| +++ b/include/drm/bridge/dw_hdmi.h |
| @@ -27,6 +27,16 @@ enum dw_hdmi_devtype { |
| RK3288_HDMI, |
| }; |
| |
| +enum dw_hdmi_phy_type { |
| + DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00, |
| + DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2, |
| + DW_HDMI_PHY_DWC_MHL_PHY = 0xc2, |
| + DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC = 0xe2, |
| + DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY = 0xf2, |
| + DW_HDMI_PHY_DWC_HDMI20_TX_PHY = 0xf3, |
| + DW_HDMI_PHY_VENDOR_PHY = 0xfe, |
| +}; |
| + |
| struct dw_hdmi_mpll_config { |
| unsigned long mpixelclock; |
| struct { |