FROMLIST: drm: bridge: dw-hdmi: Fix the PHY power up sequence
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Sun, 5 Mar 2017 23:35:57 +0000 (01:35 +0200)
committerZheng Yang <zhengyang@rock-chips.com>
Fri, 28 Apr 2017 08:20:37 +0000 (16:20 +0800)
When powering the PHY up we need to wait for the PLL to lock. This is
done by polling the TX_PHY_LOCK bit in the HDMI_PHY_STAT0 register
(interrupt-based wait could be implemented as well but is likely
overkill). The bit is asserted when the PLL locks, but the current code
incorrectly waits for the bit to be deasserted. Fix it, and while at it,
replace the udelay() with a sleep as the code never runs in
non-sleepable context.

To be consistent with the power down implementation move the poll loop
to the power off function.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170305233557.11945-1-laurent.pinchart+renesas@ideasonboard.com
Change-Id: Ibdbb87b7474a6137698692480f11ee61cd429f8e
Signed-off-by: Zheng Yang <zhengyang@rock-chips.com>
(am from https://patchwork.kernel.org/patch/9604815/)

drivers/gpu/drm/bridge/dw-hdmi.c

index 1029938ec8e932c91469021052607131a9c2d171..26af54a3a9b4c98eb712081afd9f773e07d2edd2 100644 (file)
@@ -1228,13 +1228,49 @@ static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
        dw_hdmi_phy_gen2_pddq(hdmi, 1);
 }
 
+static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi)
+{
+       const struct dw_hdmi_phy_data *phy = hdmi->phy;
+       unsigned int i;
+       u8 val;
+
+       if (phy->gen == 1) {
+               dw_hdmi_phy_enable_powerdown(hdmi, false);
+
+               /* Toggle TMDS enable. */
+               dw_hdmi_phy_enable_tmds(hdmi, 0);
+               dw_hdmi_phy_enable_tmds(hdmi, 1);
+               return 0;
+       }
+
+       dw_hdmi_phy_gen2_txpwron(hdmi, 1);
+       dw_hdmi_phy_gen2_pddq(hdmi, 0);
+
+       /* Wait for PHY PLL lock */
+       for (i = 0; i < 5; ++i) {
+               val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+               if (val)
+                       break;
+
+               usleep_range(1000, 2000);
+       }
+
+       if (!val) {
+               dev_err(hdmi->dev, "PHY PLL failed to lock\n");
+               return -ETIMEDOUT;
+       }
+
+       dev_dbg(hdmi->dev, "PHY PLL locked %u iterations\n", i);
+       return 0;
+}
+
 static int hdmi_phy_configure(struct dw_hdmi *hdmi)
 {
-       u8 val, msec, tmds_cfg;
        const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
        const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
        const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
        const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
+       u8 tmds_cfg;
 
        /* PLL/MPLL Cfg - always match on final entry */
        for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
@@ -1317,39 +1353,11 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
        hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE,
                           HDMI_3D_TX_PHY_CKCALCTRL);
 
-       dw_hdmi_phy_enable_powerdown(hdmi, false);
-
-       /* toggle TMDS disable */
-       dw_hdmi_phy_enable_tmds(hdmi, 0);
-
        /* Wait for resuming transmission of TMDS clock and data */
        if (mpll_config->mpixelclock > 340000000)
                msleep(100);
 
-       /* toggle TMDS enable */
-       dw_hdmi_phy_enable_tmds(hdmi, 1);
-
-       /* gen2 tx power on */
-       dw_hdmi_phy_gen2_txpwron(hdmi, 1);
-       dw_hdmi_phy_gen2_pddq(hdmi, 0);
-
-       /* Wait for PHY PLL lock */
-       msec = 5;
-       do {
-               val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
-               if (!val)
-                       break;
-
-               if (msec == 0) {
-                       dev_err(hdmi->dev, "PHY PLL not locked\n");
-                       return -ETIMEDOUT;
-               }
-
-               udelay(1000);
-               msec--;
-       } while (1);
-
-       return 0;
+       return dw_hdmi_phy_power_on(hdmi);
 }
 
 static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)