diff options
author | Tony Lindgren <tony@atomide.com> | 2019-02-07 10:45:16 -0500 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2019-03-18 05:42:14 -0400 |
commit | fe4ed1b457943113ee1138c939fbdeede4af6cf3 (patch) | |
tree | 1e2ecf34f7d5e5beb68a8ae2afd34f686422e40e /drivers/gpu/drm/omapdrm/dss/dsi.c | |
parent | a0970e87b5d357c8a1ec9c18e128a8d7921c29f9 (diff) |
drm/omap: dsi: Fix PM for display blank with paired dss_pll calls
Currently dsi_display_init_dsi() calls dss_pll_enable() but it is not
paired with dss_pll_disable() in dsi_display_uninit_dsi(). This leaves
the DSS clocks enabled when the display is blanked wasting about extra
5mW of power while idle.
The clock that is left on by not calling dss_pll_disable() is
DSS_CLKCTRL bit 10 OPTFCLKEN_SYS_CLK that is the source clock for
DSI PLL.
We can fix this issue by by making the current dsi_pll_uninit() into
dsi_pll_disable(). This way we can just call dss_pll_disable() from
dsi_display_uninit_dsi() and the code becomes a bit easier to follow.
However, we need to also consider that DSI PLL can be muxed for DVI too
as pointed out by Tomi Valkeinen <tomi.valkeinen@ti.com>. In the DVI
case, we want to unconditionally disable the clocks. To get around this
issue, we separate out the DSI lane handling from dsi_pll_enable() and
dsi_pll_disable() as suggested by Tomi in an earlier experimental patch.
So we must only toggle the DSI regulator based on the vdds_dsi_enabled
flag from dsi_display_init_dsi() and dsi_display_uninit_dsi().
We need to make these two changes together to avoid breaking things
for DVI when fixing the DSI clock handling. And this all causes a
slight renumbering of the error path for dsi_display_init_dsi().
Suggested-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/gpu/drm/omapdrm/dss/dsi.c')
-rw-r--r-- | drivers/gpu/drm/omapdrm/dss/dsi.c | 60 |
1 files changed, 31 insertions, 29 deletions
diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 5c34fba51975..5202862d89b5 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c | |||
@@ -1342,12 +1342,9 @@ static int dsi_pll_enable(struct dss_pll *pll) | |||
1342 | */ | 1342 | */ |
1343 | dsi_enable_scp_clk(dsi); | 1343 | dsi_enable_scp_clk(dsi); |
1344 | 1344 | ||
1345 | if (!dsi->vdds_dsi_enabled) { | 1345 | r = regulator_enable(dsi->vdds_dsi_reg); |
1346 | r = regulator_enable(dsi->vdds_dsi_reg); | 1346 | if (r) |
1347 | if (r) | 1347 | goto err0; |
1348 | goto err0; | ||
1349 | dsi->vdds_dsi_enabled = true; | ||
1350 | } | ||
1351 | 1348 | ||
1352 | /* XXX PLL does not come out of reset without this... */ | 1349 | /* XXX PLL does not come out of reset without this... */ |
1353 | dispc_pck_free_enable(dsi->dss->dispc, 1); | 1350 | dispc_pck_free_enable(dsi->dss->dispc, 1); |
@@ -1372,36 +1369,25 @@ static int dsi_pll_enable(struct dss_pll *pll) | |||
1372 | 1369 | ||
1373 | return 0; | 1370 | return 0; |
1374 | err1: | 1371 | err1: |
1375 | if (dsi->vdds_dsi_enabled) { | 1372 | regulator_disable(dsi->vdds_dsi_reg); |
1376 | regulator_disable(dsi->vdds_dsi_reg); | ||
1377 | dsi->vdds_dsi_enabled = false; | ||
1378 | } | ||
1379 | err0: | 1373 | err0: |
1380 | dsi_disable_scp_clk(dsi); | 1374 | dsi_disable_scp_clk(dsi); |
1381 | dsi_runtime_put(dsi); | 1375 | dsi_runtime_put(dsi); |
1382 | return r; | 1376 | return r; |
1383 | } | 1377 | } |
1384 | 1378 | ||
1385 | static void dsi_pll_uninit(struct dsi_data *dsi, bool disconnect_lanes) | 1379 | static void dsi_pll_disable(struct dss_pll *pll) |
1386 | { | 1380 | { |
1381 | struct dsi_data *dsi = container_of(pll, struct dsi_data, pll); | ||
1382 | |||
1387 | dsi_pll_power(dsi, DSI_PLL_POWER_OFF); | 1383 | dsi_pll_power(dsi, DSI_PLL_POWER_OFF); |
1388 | if (disconnect_lanes) { | 1384 | |
1389 | WARN_ON(!dsi->vdds_dsi_enabled); | 1385 | regulator_disable(dsi->vdds_dsi_reg); |
1390 | regulator_disable(dsi->vdds_dsi_reg); | ||
1391 | dsi->vdds_dsi_enabled = false; | ||
1392 | } | ||
1393 | 1386 | ||
1394 | dsi_disable_scp_clk(dsi); | 1387 | dsi_disable_scp_clk(dsi); |
1395 | dsi_runtime_put(dsi); | 1388 | dsi_runtime_put(dsi); |
1396 | 1389 | ||
1397 | DSSDBG("PLL uninit done\n"); | 1390 | DSSDBG("PLL disable done\n"); |
1398 | } | ||
1399 | |||
1400 | static void dsi_pll_disable(struct dss_pll *pll) | ||
1401 | { | ||
1402 | struct dsi_data *dsi = container_of(pll, struct dsi_data, pll); | ||
1403 | |||
1404 | dsi_pll_uninit(dsi, true); | ||
1405 | } | 1391 | } |
1406 | 1392 | ||
1407 | static int dsi_dump_dsi_clocks(struct seq_file *s, void *p) | 1393 | static int dsi_dump_dsi_clocks(struct seq_file *s, void *p) |
@@ -4089,11 +4075,11 @@ static int dsi_display_init_dsi(struct dsi_data *dsi) | |||
4089 | 4075 | ||
4090 | r = dss_pll_enable(&dsi->pll); | 4076 | r = dss_pll_enable(&dsi->pll); |
4091 | if (r) | 4077 | if (r) |
4092 | goto err0; | 4078 | return r; |
4093 | 4079 | ||
4094 | r = dsi_configure_dsi_clocks(dsi); | 4080 | r = dsi_configure_dsi_clocks(dsi); |
4095 | if (r) | 4081 | if (r) |
4096 | goto err1; | 4082 | goto err0; |
4097 | 4083 | ||
4098 | dss_select_dsi_clk_source(dsi->dss, dsi->module_id, | 4084 | dss_select_dsi_clk_source(dsi->dss, dsi->module_id, |
4099 | dsi->module_id == 0 ? | 4085 | dsi->module_id == 0 ? |
@@ -4101,6 +4087,14 @@ static int dsi_display_init_dsi(struct dsi_data *dsi) | |||
4101 | 4087 | ||
4102 | DSSDBG("PLL OK\n"); | 4088 | DSSDBG("PLL OK\n"); |
4103 | 4089 | ||
4090 | if (!dsi->vdds_dsi_enabled) { | ||
4091 | r = regulator_enable(dsi->vdds_dsi_reg); | ||
4092 | if (r) | ||
4093 | goto err1; | ||
4094 | |||
4095 | dsi->vdds_dsi_enabled = true; | ||
4096 | } | ||
4097 | |||
4104 | r = dsi_cio_init(dsi); | 4098 | r = dsi_cio_init(dsi); |
4105 | if (r) | 4099 | if (r) |
4106 | goto err2; | 4100 | goto err2; |
@@ -4129,10 +4123,13 @@ static int dsi_display_init_dsi(struct dsi_data *dsi) | |||
4129 | err3: | 4123 | err3: |
4130 | dsi_cio_uninit(dsi); | 4124 | dsi_cio_uninit(dsi); |
4131 | err2: | 4125 | err2: |
4132 | dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); | 4126 | regulator_disable(dsi->vdds_dsi_reg); |
4127 | dsi->vdds_dsi_enabled = false; | ||
4133 | err1: | 4128 | err1: |
4134 | dss_pll_disable(&dsi->pll); | 4129 | dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); |
4135 | err0: | 4130 | err0: |
4131 | dss_pll_disable(&dsi->pll); | ||
4132 | |||
4136 | return r; | 4133 | return r; |
4137 | } | 4134 | } |
4138 | 4135 | ||
@@ -4151,7 +4148,12 @@ static void dsi_display_uninit_dsi(struct dsi_data *dsi, bool disconnect_lanes, | |||
4151 | 4148 | ||
4152 | dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); | 4149 | dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK); |
4153 | dsi_cio_uninit(dsi); | 4150 | dsi_cio_uninit(dsi); |
4154 | dsi_pll_uninit(dsi, disconnect_lanes); | 4151 | dss_pll_disable(&dsi->pll); |
4152 | |||
4153 | if (disconnect_lanes) { | ||
4154 | regulator_disable(dsi->vdds_dsi_reg); | ||
4155 | dsi->vdds_dsi_enabled = false; | ||
4156 | } | ||
4155 | } | 4157 | } |
4156 | 4158 | ||
4157 | static void dsi_display_enable(struct omap_dss_device *dssdev) | 4159 | static void dsi_display_enable(struct omap_dss_device *dssdev) |