From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> To: dri-devel@lists.freedesktop.org Cc: Archit Taneja <architt@codeaurora.org>, Fabio Estevam <fabio.estevam@freescale.com>, Jose Abreu <Jose.Abreu@synopsys.com>, Neil Armstrong <narmstrong@baylibre.com>, Kieran Bingham <kieran.bingham@ideasonboard.com>, linux-renesas-soc@vger.kernel.org, Nickey Yang <nickey.yang@rock-chips.com>, Russell King <rmk+kernel@arm.linux.org.uk>, Andy Yan <andy.yan@rock-chips.com>, Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com> Subject: [PATCH v5.1 04/10] drm: bridge: dw-hdmi: Fix the PHY power down sequence Date: Mon, 6 Mar 2017 01:35:39 +0200 [thread overview] Message-ID: <20170305233539.11898-1-laurent.pinchart+renesas@ideasonboard.com> (raw) In-Reply-To: <20170303172007.26541-5-laurent.pinchart+renesas@ideasonboard.com> The PHY requires us to wait for the PHY to switch to low power mode after deasserting TXPWRON and before asserting PDDQ in the power down sequence, otherwise power down will fail. The PHY power down can be monitored though the TX_READY bit, available through I2C in the PHY registers, or the TX_PHY_LOCK bit, available through the HDMI TX registers. As the two are equivalent, let's pick the easier solution of polling the TX_PHY_LOCK bit. The power down code is currently duplicated in multiple places. To avoid spreading multiple calls to a TX_PHY_LOCK poll function, we have to refactor the power down code and group it all in a single function. Tests showed that one poll iteration was enough for TX_PHY_LOCK to become low, without requiring any additional delay. Retrying the read five times with a 1ms to 2ms delay between each attempt should thus be more than enough. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Tested-by: Neil Armstrong <narmstrong@baylibre.com> Reviewed-by: Jose Abreu <joabreu@synopsys.com> --- drivers/gpu/drm/bridge/dw-hdmi.c | 52 +++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 9 deletions(-) Changes since v5: - Fix compilation breakage due to reordering of the patches compared to v4 diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index d863b3393aee..3a1cd4c7ac64 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -116,6 +116,7 @@ struct dw_hdmi_i2c { struct dw_hdmi_phy_data { enum dw_hdmi_phy_type type; const char *name; + unsigned int gen; bool has_svsret; }; @@ -914,6 +915,40 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable) HDMI_PHY_CONF0_SELDIPIF_MASK); } +static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi) +{ + const struct dw_hdmi_phy_data *phy = hdmi->phy; + unsigned int i; + u16 val; + + if (phy->gen == 1) { + dw_hdmi_phy_enable_tmds(hdmi, 0); + dw_hdmi_phy_enable_powerdown(hdmi, true); + return; + } + + dw_hdmi_phy_gen2_txpwron(hdmi, 0); + + /* + * Wait for TX_PHY_LOCK to be deasserted to indicate that the PHY went + * to low power mode. + */ + for (i = 0; i < 5; ++i) { + val = hdmi_readb(hdmi, HDMI_PHY_STAT0); + if (!(val & HDMI_PHY_TX_PHY_LOCK)) + break; + + usleep_range(1000, 2000); + } + + if (val & HDMI_PHY_TX_PHY_LOCK) + dev_warn(hdmi->dev, "PHY failed to power down\n"); + else + dev_dbg(hdmi->dev, "PHY powered down in %u iterations\n", i); + + dw_hdmi_phy_gen2_pddq(hdmi, 1); +} + static int hdmi_phy_configure(struct dw_hdmi *hdmi) { u8 val, msec; @@ -946,11 +981,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) return -EINVAL; } - /* gen2 tx power off */ - dw_hdmi_phy_gen2_txpwron(hdmi, 0); - - /* gen2 pddq */ - dw_hdmi_phy_gen2_pddq(hdmi, 1); + dw_hdmi_phy_power_off(hdmi); /* Leave low power consumption mode by asserting SVSRET. */ if (hdmi->phy->has_svsret) @@ -1025,8 +1056,6 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi) for (i = 0; i < 2; i++) { dw_hdmi_phy_sel_data_en_pol(hdmi, 1); dw_hdmi_phy_sel_interface_control(hdmi, 0); - dw_hdmi_phy_enable_tmds(hdmi, 0); - dw_hdmi_phy_enable_powerdown(hdmi, true); ret = hdmi_phy_configure(hdmi); if (ret) @@ -1256,8 +1285,7 @@ static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi) if (!hdmi->phy_enabled) return; - dw_hdmi_phy_enable_tmds(hdmi, 0); - dw_hdmi_phy_enable_powerdown(hdmi, true); + dw_hdmi_phy_power_off(hdmi); hdmi->phy_enabled = false; } @@ -1827,23 +1855,29 @@ static const struct dw_hdmi_phy_data dw_hdmi_phys[] = { { .type = DW_HDMI_PHY_DWC_HDMI_TX_PHY, .name = "DWC HDMI TX PHY", + .gen = 1, }, { .type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC, .name = "DWC MHL PHY + HEAC PHY", + .gen = 2, .has_svsret = true, }, { .type = DW_HDMI_PHY_DWC_MHL_PHY, .name = "DWC MHL PHY", + .gen = 2, .has_svsret = true, }, { .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC, .name = "DWC HDMI 3D TX PHY + HEAC PHY", + .gen = 2, }, { .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY, .name = "DWC HDMI 3D TX PHY", + .gen = 2, }, { .type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY, .name = "DWC HDMI 2.0 TX PHY", + .gen = 2, .has_svsret = true, } }; -- Regards, Laurent Pinchart
WARNING: multiple messages have this Message-ID (diff)
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> To: dri-devel@lists.freedesktop.org Cc: Fabio Estevam <fabio.estevam@freescale.com>, Jose Abreu <Jose.Abreu@synopsys.com>, Neil Armstrong <narmstrong@baylibre.com>, Kieran Bingham <kieran.bingham@ideasonboard.com>, linux-renesas-soc@vger.kernel.org, Nickey Yang <nickey.yang@rock-chips.com>, Andy Yan <andy.yan@rock-chips.com>, Russell King <rmk+kernel@arm.linux.org.uk>, Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com> Subject: [PATCH v5.1 04/10] drm: bridge: dw-hdmi: Fix the PHY power down sequence Date: Mon, 6 Mar 2017 01:35:39 +0200 [thread overview] Message-ID: <20170305233539.11898-1-laurent.pinchart+renesas@ideasonboard.com> (raw) In-Reply-To: <20170303172007.26541-5-laurent.pinchart+renesas@ideasonboard.com> The PHY requires us to wait for the PHY to switch to low power mode after deasserting TXPWRON and before asserting PDDQ in the power down sequence, otherwise power down will fail. The PHY power down can be monitored though the TX_READY bit, available through I2C in the PHY registers, or the TX_PHY_LOCK bit, available through the HDMI TX registers. As the two are equivalent, let's pick the easier solution of polling the TX_PHY_LOCK bit. The power down code is currently duplicated in multiple places. To avoid spreading multiple calls to a TX_PHY_LOCK poll function, we have to refactor the power down code and group it all in a single function. Tests showed that one poll iteration was enough for TX_PHY_LOCK to become low, without requiring any additional delay. Retrying the read five times with a 1ms to 2ms delay between each attempt should thus be more than enough. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Tested-by: Neil Armstrong <narmstrong@baylibre.com> Reviewed-by: Jose Abreu <joabreu@synopsys.com> --- drivers/gpu/drm/bridge/dw-hdmi.c | 52 +++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 9 deletions(-) Changes since v5: - Fix compilation breakage due to reordering of the patches compared to v4 diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index d863b3393aee..3a1cd4c7ac64 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -116,6 +116,7 @@ struct dw_hdmi_i2c { struct dw_hdmi_phy_data { enum dw_hdmi_phy_type type; const char *name; + unsigned int gen; bool has_svsret; }; @@ -914,6 +915,40 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable) HDMI_PHY_CONF0_SELDIPIF_MASK); } +static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi) +{ + const struct dw_hdmi_phy_data *phy = hdmi->phy; + unsigned int i; + u16 val; + + if (phy->gen == 1) { + dw_hdmi_phy_enable_tmds(hdmi, 0); + dw_hdmi_phy_enable_powerdown(hdmi, true); + return; + } + + dw_hdmi_phy_gen2_txpwron(hdmi, 0); + + /* + * Wait for TX_PHY_LOCK to be deasserted to indicate that the PHY went + * to low power mode. + */ + for (i = 0; i < 5; ++i) { + val = hdmi_readb(hdmi, HDMI_PHY_STAT0); + if (!(val & HDMI_PHY_TX_PHY_LOCK)) + break; + + usleep_range(1000, 2000); + } + + if (val & HDMI_PHY_TX_PHY_LOCK) + dev_warn(hdmi->dev, "PHY failed to power down\n"); + else + dev_dbg(hdmi->dev, "PHY powered down in %u iterations\n", i); + + dw_hdmi_phy_gen2_pddq(hdmi, 1); +} + static int hdmi_phy_configure(struct dw_hdmi *hdmi) { u8 val, msec; @@ -946,11 +981,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) return -EINVAL; } - /* gen2 tx power off */ - dw_hdmi_phy_gen2_txpwron(hdmi, 0); - - /* gen2 pddq */ - dw_hdmi_phy_gen2_pddq(hdmi, 1); + dw_hdmi_phy_power_off(hdmi); /* Leave low power consumption mode by asserting SVSRET. */ if (hdmi->phy->has_svsret) @@ -1025,8 +1056,6 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi) for (i = 0; i < 2; i++) { dw_hdmi_phy_sel_data_en_pol(hdmi, 1); dw_hdmi_phy_sel_interface_control(hdmi, 0); - dw_hdmi_phy_enable_tmds(hdmi, 0); - dw_hdmi_phy_enable_powerdown(hdmi, true); ret = hdmi_phy_configure(hdmi); if (ret) @@ -1256,8 +1285,7 @@ static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi) if (!hdmi->phy_enabled) return; - dw_hdmi_phy_enable_tmds(hdmi, 0); - dw_hdmi_phy_enable_powerdown(hdmi, true); + dw_hdmi_phy_power_off(hdmi); hdmi->phy_enabled = false; } @@ -1827,23 +1855,29 @@ static const struct dw_hdmi_phy_data dw_hdmi_phys[] = { { .type = DW_HDMI_PHY_DWC_HDMI_TX_PHY, .name = "DWC HDMI TX PHY", + .gen = 1, }, { .type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC, .name = "DWC MHL PHY + HEAC PHY", + .gen = 2, .has_svsret = true, }, { .type = DW_HDMI_PHY_DWC_MHL_PHY, .name = "DWC MHL PHY", + .gen = 2, .has_svsret = true, }, { .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC, .name = "DWC HDMI 3D TX PHY + HEAC PHY", + .gen = 2, }, { .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY, .name = "DWC HDMI 3D TX PHY", + .gen = 2, }, { .type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY, .name = "DWC HDMI 2.0 TX PHY", + .gen = 2, .has_svsret = true, } }; -- Regards, Laurent Pinchart _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
next prev parent reply other threads:[~2017-03-05 23:44 UTC|newest] Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top 2017-03-03 17:19 [PATCH v5 00/10] drm: bridge: dw-hdmi: Refactor PHY support Laurent Pinchart 2017-03-03 17:19 ` Laurent Pinchart 2017-03-03 17:19 ` [PATCH v5 01/10] drm: bridge: dw-hdmi: Remove unused functions Laurent Pinchart 2017-03-03 17:19 ` Laurent Pinchart 2017-03-04 1:11 ` [PATCH v5.1 10/10] drm: bridge: dw-hdmi: Move the driver to a separate directory Laurent Pinchart 2017-03-04 1:11 ` Laurent Pinchart 2017-03-03 17:19 ` [PATCH v5 02/10] drm: bridge: dw-hdmi: Move CSC configuration out of PHY code Laurent Pinchart 2017-03-03 17:19 ` Laurent Pinchart 2017-03-03 17:20 ` [PATCH v5 03/10] drm: bridge: dw-hdmi: Enable CSC even for DVI Laurent Pinchart 2017-03-03 17:20 ` Laurent Pinchart 2017-03-03 17:20 ` [PATCH v5 04/10] drm: bridge: dw-hdmi: Fix the PHY power down sequence Laurent Pinchart 2017-03-03 17:20 ` Laurent Pinchart 2017-03-05 23:35 ` Laurent Pinchart [this message] 2017-03-05 23:35 ` [PATCH v5.1 " Laurent Pinchart 2017-03-03 17:20 ` [PATCH v5 05/10] drm: bridge: dw-hdmi: Fix the PHY power up sequence Laurent Pinchart 2017-03-03 17:20 ` Laurent Pinchart 2017-03-05 23:35 ` [PATCH v5.1 " Laurent Pinchart 2017-03-05 23:35 ` Laurent Pinchart 2017-03-03 17:20 ` [PATCH v5 06/10] drm: bridge: dw-hdmi: Create PHY operations Laurent Pinchart 2017-03-03 17:20 ` Laurent Pinchart 2017-03-05 23:36 ` [PATCH v5.1 " Laurent Pinchart 2017-03-05 23:36 ` Laurent Pinchart 2017-03-03 17:20 ` [PATCH v5 07/10] drm: bridge: dw-hdmi: Add support for custom PHY configuration Laurent Pinchart 2017-03-03 17:20 ` Laurent Pinchart 2017-04-24 7:46 ` 郑阳 2017-04-26 11:04 ` Jose Abreu 2017-04-27 4:16 ` 郑阳 2017-03-03 17:20 ` [PATCH v5 08/10] drm: bridge: dw-hdmi: Remove device type from platform data Laurent Pinchart 2017-03-03 17:20 ` Laurent Pinchart 2017-03-03 17:20 ` [PATCH v5 09/10] drm: bridge: dw-hdmi: Switch to regmap for register access Laurent Pinchart 2017-03-03 17:20 ` Laurent Pinchart 2017-03-03 17:20 ` [PATCH v5 10/10] drm: bridge: dw-hdmi: Move the driver to a separate directory Laurent Pinchart 2017-03-03 17:20 ` Laurent Pinchart 2017-03-10 11:10 ` [PATCH v5 00/10] drm: bridge: dw-hdmi: Refactor PHY support Archit Taneja 2017-03-10 11:10 ` Archit Taneja
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20170305233539.11898-1-laurent.pinchart+renesas@ideasonboard.com \ --to=laurent.pinchart+renesas@ideasonboard.com \ --cc=Jose.Abreu@synopsys.com \ --cc=andy.yan@rock-chips.com \ --cc=architt@codeaurora.org \ --cc=dri-devel@lists.freedesktop.org \ --cc=fabio.estevam@freescale.com \ --cc=kieran.bingham@ideasonboard.com \ --cc=linux-renesas-soc@vger.kernel.org \ --cc=narmstrong@baylibre.com \ --cc=nickey.yang@rock-chips.com \ --cc=rmk+kernel@arm.linux.org.uk \ --cc=vladimir_zapolskiy@mentor.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.