Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: bridge: dw-hdmi: Move HPD handling to PHY operations

The HDMI TX controller support HPD and RXSENSE signaling from the PHY
via it's STAT0 PHY interface, but some vendor PHYs can manage these
signals independently from the controller, thus these STAT0 handling
should be moved to PHY specific operations and become optional.

The existing STAT0 HPD and RXSENSE handling code is refactored into
a supplementaty set of default PHY operations that are used automatically
when the platform glue doesn't provide its own operations.

Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Reviewed-by: Archit Taneja <architt@codeaurora.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1491309119-24220-2-git-send-email-narmstrong@baylibre.com

+86 -54
+81 -54
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
··· 1229 1229 connector_status_connected : connector_status_disconnected; 1230 1230 } 1231 1231 1232 + static void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data, 1233 + bool force, bool disabled, bool rxsense) 1234 + { 1235 + u8 old_mask = hdmi->phy_mask; 1236 + 1237 + if (force || disabled || !rxsense) 1238 + hdmi->phy_mask |= HDMI_PHY_RX_SENSE; 1239 + else 1240 + hdmi->phy_mask &= ~HDMI_PHY_RX_SENSE; 1241 + 1242 + if (old_mask != hdmi->phy_mask) 1243 + hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); 1244 + } 1245 + 1246 + static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data) 1247 + { 1248 + /* 1249 + * Configure the PHY RX SENSE and HPD interrupts polarities and clear 1250 + * any pending interrupt. 1251 + */ 1252 + hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0); 1253 + hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, 1254 + HDMI_IH_PHY_STAT0); 1255 + 1256 + /* Enable cable hot plug irq. */ 1257 + hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); 1258 + 1259 + /* Clear and unmute interrupts. */ 1260 + hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, 1261 + HDMI_IH_PHY_STAT0); 1262 + hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE), 1263 + HDMI_IH_MUTE_PHY_STAT0); 1264 + } 1265 + 1232 1266 static const struct dw_hdmi_phy_ops dw_hdmi_synopsys_phy_ops = { 1233 1267 .init = dw_hdmi_phy_init, 1234 1268 .disable = dw_hdmi_phy_disable, 1235 1269 .read_hpd = dw_hdmi_phy_read_hpd, 1270 + .update_hpd = dw_hdmi_phy_update_hpd, 1271 + .setup_hpd = dw_hdmi_phy_setup_hpd, 1236 1272 }; 1237 1273 1238 1274 /* ----------------------------------------------------------------------------- ··· 1844 1808 */ 1845 1809 static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) 1846 1810 { 1847 - u8 old_mask = hdmi->phy_mask; 1848 - 1849 - if (hdmi->force || hdmi->disabled || !hdmi->rxsense) 1850 - hdmi->phy_mask |= HDMI_PHY_RX_SENSE; 1851 - else 1852 - hdmi->phy_mask &= ~HDMI_PHY_RX_SENSE; 1853 - 1854 - if (old_mask != hdmi->phy_mask) 1855 - hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); 1856 - } 1857 - 1858 - static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi) 1859 - { 1860 - /* 1861 - * Configure the PHY RX SENSE and HPD interrupts polarities and clear 1862 - * any pending interrupt. 1863 - */ 1864 - hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0); 1865 - hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, 1866 - HDMI_IH_PHY_STAT0); 1867 - 1868 - /* Enable cable hot plug irq. */ 1869 - hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0); 1870 - 1871 - /* Clear and unmute interrupts. */ 1872 - hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE, 1873 - HDMI_IH_PHY_STAT0); 1874 - hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE), 1875 - HDMI_IH_MUTE_PHY_STAT0); 1811 + if (hdmi->phy.ops->update_hpd) 1812 + hdmi->phy.ops->update_hpd(hdmi, hdmi->phy.data, 1813 + hdmi->force, hdmi->disabled, 1814 + hdmi->rxsense); 1876 1815 } 1877 1816 1878 1817 static enum drm_connector_status ··· 2039 2028 return ret; 2040 2029 } 2041 2030 2031 + void __dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense) 2032 + { 2033 + mutex_lock(&hdmi->mutex); 2034 + 2035 + if (!hdmi->force) { 2036 + /* 2037 + * If the RX sense status indicates we're disconnected, 2038 + * clear the software rxsense status. 2039 + */ 2040 + if (!rx_sense) 2041 + hdmi->rxsense = false; 2042 + 2043 + /* 2044 + * Only set the software rxsense status when both 2045 + * rxsense and hpd indicates we're connected. 2046 + * This avoids what seems to be bad behaviour in 2047 + * at least iMX6S versions of the phy. 2048 + */ 2049 + if (hpd) 2050 + hdmi->rxsense = true; 2051 + 2052 + dw_hdmi_update_power(hdmi); 2053 + dw_hdmi_update_phy_mask(hdmi); 2054 + } 2055 + mutex_unlock(&hdmi->mutex); 2056 + } 2057 + 2058 + void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense) 2059 + { 2060 + struct dw_hdmi *hdmi = dev_get_drvdata(dev); 2061 + 2062 + __dw_hdmi_setup_rx_sense(hdmi, hpd, rx_sense); 2063 + } 2064 + EXPORT_SYMBOL_GPL(dw_hdmi_setup_rx_sense); 2065 + 2042 2066 static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) 2043 2067 { 2044 2068 struct dw_hdmi *hdmi = dev_id; ··· 2106 2060 * ask the source to re-read the EDID. 2107 2061 */ 2108 2062 if (intr_stat & 2109 - (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) { 2110 - mutex_lock(&hdmi->mutex); 2111 - if (!hdmi->force) { 2112 - /* 2113 - * If the RX sense status indicates we're disconnected, 2114 - * clear the software rxsense status. 2115 - */ 2116 - if (!(phy_stat & HDMI_PHY_RX_SENSE)) 2117 - hdmi->rxsense = false; 2118 - 2119 - /* 2120 - * Only set the software rxsense status when both 2121 - * rxsense and hpd indicates we're connected. 2122 - * This avoids what seems to be bad behaviour in 2123 - * at least iMX6S versions of the phy. 2124 - */ 2125 - if (phy_stat & HDMI_PHY_HPD) 2126 - hdmi->rxsense = true; 2127 - 2128 - dw_hdmi_update_power(hdmi); 2129 - dw_hdmi_update_phy_mask(hdmi); 2130 - } 2131 - mutex_unlock(&hdmi->mutex); 2132 - } 2063 + (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) 2064 + __dw_hdmi_setup_rx_sense(hdmi, 2065 + phy_stat & HDMI_PHY_HPD, 2066 + phy_stat & HDMI_PHY_RX_SENSE); 2133 2067 2134 2068 if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { 2135 2069 dev_dbg(hdmi->dev, "EVENT=%s\n", ··· 2383 2357 #endif 2384 2358 2385 2359 dw_hdmi_setup_i2c(hdmi); 2386 - dw_hdmi_phy_setup_hpd(hdmi); 2360 + if (hdmi->phy.ops->setup_hpd) 2361 + hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data); 2387 2362 2388 2363 memset(&pdevinfo, 0, sizeof(pdevinfo)); 2389 2364 pdevinfo.parent = dev;
+5
include/drm/bridge/dw_hdmi.h
··· 117 117 struct drm_display_mode *mode); 118 118 void (*disable)(struct dw_hdmi *hdmi, void *data); 119 119 enum drm_connector_status (*read_hpd)(struct dw_hdmi *hdmi, void *data); 120 + void (*update_hpd)(struct dw_hdmi *hdmi, void *data, 121 + bool force, bool disabled, bool rxsense); 122 + void (*setup_hpd)(struct dw_hdmi *hdmi, void *data); 120 123 }; 121 124 122 125 struct dw_hdmi_plat_data { ··· 149 146 void dw_hdmi_unbind(struct device *dev); 150 147 int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, 151 148 const struct dw_hdmi_plat_data *plat_data); 149 + 150 + void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense); 152 151 153 152 void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate); 154 153 void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);