disp: msm: sde: unset and set clk parents during pm_suspend

Currently link clk parent set/unset are done as part of dsi_prepare
and dsi_unprepare, but in case of deepsleep with display ON, these
will not be called. Due to mismatch in parent between clk
framework and actual parent, subsequent clk_set_parent will
early return without setting the parent.

To avoid this condition, do set parent to xo, as part of
pm_suspend and restore to link clk source in pm_resume.

Change-Id: I626899304580f9d9fbcc92cd8b139cd89cd48999
Signed-off-by: Venkata Prahlad Valluru <quic_vvalluru@quicinc.com>
This commit is contained in:
Venkata Prahlad Valluru 2022-04-12 22:36:32 +05:30
commit 9a6ed8620e
3 changed files with 67 additions and 3 deletions

View file

@ -2659,7 +2659,7 @@ error:
}
#ifdef CONFIG_DEEPSLEEP
static int dsi_display_unset_clk_src(struct dsi_display *display)
int dsi_display_unset_clk_src(struct dsi_display *display)
{
int rc = 0;
int i;
@ -2684,13 +2684,13 @@ static int dsi_display_unset_clk_src(struct dsi_display *display)
return 0;
}
#else
static inline int dsi_display_unset_clk_src(struct dsi_display *display)
inline int dsi_display_unset_clk_src(struct dsi_display *display)
{
return 0;
}
#endif
static int dsi_display_set_clk_src(struct dsi_display *display)
int dsi_display_set_clk_src(struct dsi_display *display)
{
int rc = 0;
int i;
@ -4200,6 +4200,9 @@ static int dsi_display_parse_dt(struct dsi_display *display)
/* Parse TE data */
dsi_display_parse_te_data(display);
display->needs_clk_src_reset = of_property_read_bool(of_node,
"qcom,needs-clk-src-reset");
/* Parse all external bridges from port 0 */
display_for_each_ctrl(i, display) {
display->ext_bridge[i].node_of =

View file

@ -214,6 +214,7 @@ struct dsi_display {
int disp_te_gpio;
bool is_te_irq_enabled;
struct completion esd_te_gate;
bool needs_clk_src_reset;
u32 ctrl_count;
struct dsi_display_ctrl ctrl[MAX_DSI_CTRLS_PER_DISPLAY];
@ -801,4 +802,19 @@ int dsi_display_dump_clks_state(struct dsi_display *display);
*/
void dsi_display_dfps_update_parent(struct dsi_display *display);
/**
* dsi_display_unset_clk_src() - reset the clocks source to default
* @display: Handle to display
*
* Return: Zero on Success
*/
int dsi_display_unset_clk_src(struct dsi_display *display);
/**
* dsi_display_set_clk_src() - set the clocks source
* @display: Handle to display
*
* Return: Zero on Success
*/
int dsi_display_set_clk_src(struct dsi_display *display);
#endif /* _DSI_DISPLAY_H_ */

View file

@ -27,6 +27,7 @@
#include <linux/of_irq.h>
#include <linux/dma-buf.h>
#include <linux/memblock.h>
#include <linux/suspend.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_probe_helper.h>
@ -3713,6 +3714,44 @@ void sde_kms_display_early_wakeup(struct drm_device *dev,
drm_connector_list_iter_end(&conn_iter);
}
#ifdef CONFIG_DEEPSLEEP
static int _sde_kms_pm_set_clk_src(struct sde_kms *sde_kms, bool enable)
{
int i, rc = 0;
void *display;
struct dsi_display *dsi_display;
if (mem_sleep_current == PM_SUSPEND_MEM) {
SDE_INFO("Deepsleep\n");
for (i = 0; i < sde_kms->dsi_display_count; i++) {
display = sde_kms->dsi_displays[i];
dsi_display = (struct dsi_display *)display;
if (!dsi_display->needs_clk_src_reset)
continue;
if (enable)
rc = dsi_display_set_clk_src(dsi_display);
else
rc = dsi_display_unset_clk_src(dsi_display);
if (rc) {
SDE_ERROR("failed to set clks rc:%d\n", rc);
return rc;
}
}
}
return rc;
}
#else
static inline int _sde_kms_pm_set_clk_src(struct sde_kms *sde_kms, bool enable)
{
return 0;
}
#endif
static void _sde_kms_pm_suspend_idle_helper(struct sde_kms *sde_kms,
struct device *dev)
{
@ -3904,6 +3943,9 @@ unlock:
pm_runtime_put_sync(dev);
pm_runtime_get_noresume(dev);
/* reset clock source based on PM suspend state */
_sde_kms_pm_set_clk_src(sde_kms, false);
/* dump clock state before entering suspend */
if (sde_kms->pm_suspend_clk_dump)
_sde_kms_dump_clks_state(sde_kms);
@ -3941,6 +3983,9 @@ retry:
goto end;
}
/* reset clock source based on PM suspend state */
_sde_kms_pm_set_clk_src(sde_kms, true);
sde_kms->suspend_block = false;
if (sde_kms->suspend_state) {