diff options
| -rw-r--r-- | drivers/gpu/drm/bridge/dw-hdmi.c | 68 | ||||
| -rw-r--r-- | include/drm/bridge/dw_hdmi.h | 10 |
2 files changed, 75 insertions, 3 deletions
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index f4faa14213e5..ef4f2f96ed2c 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c | |||
| @@ -113,6 +113,12 @@ struct dw_hdmi_i2c { | |||
| 113 | bool is_regaddr; | 113 | bool is_regaddr; |
| 114 | }; | 114 | }; |
| 115 | 115 | ||
| 116 | struct dw_hdmi_phy_data { | ||
| 117 | enum dw_hdmi_phy_type type; | ||
| 118 | const char *name; | ||
| 119 | bool has_svsret; | ||
| 120 | }; | ||
| 121 | |||
| 116 | struct dw_hdmi { | 122 | struct dw_hdmi { |
| 117 | struct drm_connector connector; | 123 | struct drm_connector connector; |
| 118 | struct drm_bridge bridge; | 124 | struct drm_bridge bridge; |
| @@ -134,7 +140,9 @@ struct dw_hdmi { | |||
| 134 | u8 edid[HDMI_EDID_LEN]; | 140 | u8 edid[HDMI_EDID_LEN]; |
| 135 | bool cable_plugin; | 141 | bool cable_plugin; |
| 136 | 142 | ||
| 143 | const struct dw_hdmi_phy_data *phy; | ||
| 137 | bool phy_enabled; | 144 | bool phy_enabled; |
| 145 | |||
| 138 | struct drm_display_mode previous_mode; | 146 | struct drm_display_mode previous_mode; |
| 139 | 147 | ||
| 140 | struct i2c_adapter *ddc; | 148 | struct i2c_adapter *ddc; |
| @@ -1015,7 +1023,8 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon) | |||
| 1015 | dw_hdmi_phy_gen2_txpwron(hdmi, 1); | 1023 | dw_hdmi_phy_gen2_txpwron(hdmi, 1); |
| 1016 | dw_hdmi_phy_gen2_pddq(hdmi, 0); | 1024 | dw_hdmi_phy_gen2_pddq(hdmi, 0); |
| 1017 | 1025 | ||
| 1018 | if (hdmi->dev_type == RK3288_HDMI) | 1026 | /* The DWC MHL and HDMI 2.0 PHYs need the SVSRET signal to be set. */ |
| 1027 | if (hdmi->phy->has_svsret) | ||
| 1019 | dw_hdmi_phy_enable_svsret(hdmi, 1); | 1028 | dw_hdmi_phy_enable_svsret(hdmi, 1); |
| 1020 | 1029 | ||
| 1021 | /*Wait for PHY PLL lock */ | 1030 | /*Wait for PHY PLL lock */ |
| @@ -1840,6 +1849,54 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) | |||
| 1840 | return IRQ_HANDLED; | 1849 | return IRQ_HANDLED; |
| 1841 | } | 1850 | } |
| 1842 | 1851 | ||
| 1852 | static const struct dw_hdmi_phy_data dw_hdmi_phys[] = { | ||
| 1853 | { | ||
| 1854 | .type = DW_HDMI_PHY_DWC_HDMI_TX_PHY, | ||
| 1855 | .name = "DWC HDMI TX PHY", | ||
| 1856 | }, { | ||
| 1857 | .type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC, | ||
| 1858 | .name = "DWC MHL PHY + HEAC PHY", | ||
| 1859 | .has_svsret = true, | ||
| 1860 | }, { | ||
| 1861 | .type = DW_HDMI_PHY_DWC_MHL_PHY, | ||
| 1862 | .name = "DWC MHL PHY", | ||
| 1863 | .has_svsret = true, | ||
| 1864 | }, { | ||
| 1865 | .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC, | ||
| 1866 | .name = "DWC HDMI 3D TX PHY + HEAC PHY", | ||
| 1867 | }, { | ||
| 1868 | .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY, | ||
| 1869 | .name = "DWC HDMI 3D TX PHY", | ||
| 1870 | }, { | ||
| 1871 | .type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY, | ||
| 1872 | .name = "DWC HDMI 2.0 TX PHY", | ||
| 1873 | .has_svsret = true, | ||
| 1874 | } | ||
| 1875 | }; | ||
| 1876 | |||
| 1877 | static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi) | ||
| 1878 | { | ||
| 1879 | unsigned int i; | ||
| 1880 | u8 phy_type; | ||
| 1881 | |||
| 1882 | phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID); | ||
| 1883 | |||
| 1884 | for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) { | ||
| 1885 | if (dw_hdmi_phys[i].type == phy_type) { | ||
| 1886 | hdmi->phy = &dw_hdmi_phys[i]; | ||
| 1887 | return 0; | ||
| 1888 | } | ||
| 1889 | } | ||
| 1890 | |||
| 1891 | if (phy_type == DW_HDMI_PHY_VENDOR_PHY) | ||
| 1892 | dev_err(hdmi->dev, "Unsupported vendor HDMI PHY\n"); | ||
| 1893 | else | ||
| 1894 | dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n", | ||
| 1895 | phy_type); | ||
| 1896 | |||
| 1897 | return -ENODEV; | ||
| 1898 | } | ||
| 1899 | |||
| 1843 | static struct dw_hdmi * | 1900 | static struct dw_hdmi * |
| 1844 | __dw_hdmi_probe(struct platform_device *pdev, | 1901 | __dw_hdmi_probe(struct platform_device *pdev, |
| 1845 | const struct dw_hdmi_plat_data *plat_data) | 1902 | const struct dw_hdmi_plat_data *plat_data) |
| @@ -1950,9 +2007,14 @@ __dw_hdmi_probe(struct platform_device *pdev, | |||
| 1950 | goto err_iahb; | 2007 | goto err_iahb; |
| 1951 | } | 2008 | } |
| 1952 | 2009 | ||
| 1953 | dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP\n", | 2010 | ret = dw_hdmi_detect_phy(hdmi); |
| 2011 | if (ret < 0) | ||
| 2012 | goto err_iahb; | ||
| 2013 | |||
| 2014 | dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n", | ||
| 1954 | hdmi->version >> 12, hdmi->version & 0xfff, | 2015 | hdmi->version >> 12, hdmi->version & 0xfff, |
| 1955 | prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without"); | 2016 | prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without", |
| 2017 | hdmi->phy->name); | ||
| 1956 | 2018 | ||
| 1957 | initialize_hdmi_ih_mutes(hdmi); | 2019 | initialize_hdmi_ih_mutes(hdmi); |
| 1958 | 2020 | ||
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 3bb22a849830..b080a171a23f 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h | |||
| @@ -27,6 +27,16 @@ enum dw_hdmi_devtype { | |||
| 27 | RK3288_HDMI, | 27 | RK3288_HDMI, |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | enum dw_hdmi_phy_type { | ||
| 31 | DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00, | ||
| 32 | DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2, | ||
| 33 | DW_HDMI_PHY_DWC_MHL_PHY = 0xc2, | ||
| 34 | DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC = 0xe2, | ||
| 35 | DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY = 0xf2, | ||
| 36 | DW_HDMI_PHY_DWC_HDMI20_TX_PHY = 0xf3, | ||
| 37 | DW_HDMI_PHY_VENDOR_PHY = 0xfe, | ||
| 38 | }; | ||
| 39 | |||
| 30 | struct dw_hdmi_mpll_config { | 40 | struct dw_hdmi_mpll_config { |
| 31 | unsigned long mpixelclock; | 41 | unsigned long mpixelclock; |
| 32 | struct { | 42 | struct { |
