History

drm/tegra: dsi: Enhance runtime power management

The MIPI DSI output on Tegra SoCs requires some external logic to calibrate the MIPI pads before a video signal can be transmitted. This MIPI calibration logic requires to be powered on while the MIPI pads are being used, which is currently done as part of the DSI driver's probe implementation. This is suboptimal because it will leave the MIPI calibration logic powered up even if the DSI output is never used. On Tegra114 and earlier this behaviour also causes the driver to hang while trying to power up the MIPI calibration logic because the power partition that contains the MIPI calibration logic will be powered on by the display controller at output pipeline configuration time. Thus the power up sequence for the MIPI calibration logic happens before it's power partition is guaranteed to be enabled. Fix this by splitting up the API into a request/free pair of functions that manage the runtime dependency between the DSI and the calibration modules (no registers are accessed) and a set of enable, calibrate and disable functions that program the MIPI calibration logic at points in time where the power partition is really enabled. While at it, make sure that the runtime power management also works in ganged mode, which is currently also broken.

Thierry Reding committed 10 years ago

Commit 87904c31 parent 29b48173 files · +69 −39Browse files

Unified · Split

3 files
  1. drivers/gpu/drm/tegra/dsi.c +36 −7
  2. drivers/gpu/host1x/mipi.c +31 −32
  3. include/linux/host1x.h +2 −0
drivers/gpu/drm/tegra/dsi.c+36−7
@@ -840,6 +840,21 @@ static const struct drm_encoder_funcs tegra_dsi_encoder_funcs = { · 839 unmodified lines
840840 .destroy = tegra_output_encoder_destroy,
841841 };
842842
843+static void tegra_dsi_unprepare(struct tegra_dsi *dsi)
844+{
845+ int err;
846+
847+ if (dsi->slave)
848+ tegra_dsi_unprepare(dsi->slave);
849+
850+ err = tegra_mipi_disable(dsi->mipi);
851+ if (err < 0)
852+ dev_err(dsi->dev, "failed to disable MIPI calibration: %d\n",
853+ err);
854+
855+ pm_runtime_put(dsi->dev);
856+}
857+
843858 static void tegra_dsi_encoder_disable(struct drm_encoder *encoder)
844859 {
845860 struct tegra_output *output = encoder_to_output(encoder);
@@ -876,7 +891,26 @@ static void tegra_dsi_encoder_disable(struct drm_encoder *encoder) · 30 unmodified lines
876891
877892 tegra_dsi_disable(dsi);
878893
879− pm_runtime_put(dsi->dev);
894+ tegra_dsi_unprepare(dsi);
895+}
896+
897+static void tegra_dsi_prepare(struct tegra_dsi *dsi)
898+{
899+ int err;
900+
901+ pm_runtime_get_sync(dsi->dev);
902+
903+ err = tegra_mipi_enable(dsi->mipi);
904+ if (err < 0)
905+ dev_err(dsi->dev, "failed to enable MIPI calibration: %d\n",
906+ err);
907+
908+ err = tegra_dsi_pad_calibrate(dsi);
909+ if (err < 0)
910+ dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
911+
912+ if (dsi->slave)
913+ tegra_dsi_prepare(dsi->slave);
880914 }
881915
882916 static void tegra_dsi_encoder_enable(struct drm_encoder *encoder)
@@ -887,13 +921,8 @@ static void tegra_dsi_encoder_enable(struct drm_encoder *encoder) · 4 unmodified lines
887921 struct tegra_dsi *dsi = to_dsi(output);
888922 struct tegra_dsi_state *state;
889923 u32 value;
890− int err;
891−
892− pm_runtime_get_sync(dsi->dev);
893924
894− err = tegra_dsi_pad_calibrate(dsi);
895− if (err < 0)
896− dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
925+ tegra_dsi_prepare(dsi);
897926
898927 state = tegra_dsi_get_state(dsi);
899928
drivers/gpu/host1x/mipi.c+31−32
@@ -242,20 +242,6 @@ struct tegra_mipi_device *tegra_mipi_request(struct device *device) · 241 unmodified lines
242242 dev->pads = args.args[0];
243243 dev->device = device;
244244
245− mutex_lock(&dev->mipi->lock);
246−
247− if (dev->mipi->usage_count++ == 0) {
248− err = tegra_mipi_power_up(dev->mipi);
249− if (err < 0) {
250− dev_err(dev->mipi->dev,
251− "failed to power up MIPI bricks: %d\n",
252− err);
253− return ERR_PTR(err);
254− }
255− }
256−
257− mutex_unlock(&dev->mipi->lock);
258−
259245 return dev;
260246
261247 put:
@@ -270,29 +256,42 @@ EXPORT_SYMBOL(tegra_mipi_request); · 8 unmodified lines
270256
271257 void tegra_mipi_free(struct tegra_mipi_device *device)
272258 {
273− int err;
259+ platform_device_put(device->pdev);
260+ kfree(device);
261+}
262+EXPORT_SYMBOL(tegra_mipi_free);
274263
275− mutex_lock(&device->mipi->lock);
264+int tegra_mipi_enable(struct tegra_mipi_device *dev)
265+{
266+ int err = 0;
276267
277− if (--device->mipi->usage_count == 0) {
278− err = tegra_mipi_power_down(device->mipi);
279− if (err < 0) {
280− /*
281− * Not much that can be done here, so an error message
282− * will have to do.
283− */
284− dev_err(device->mipi->dev,
285− "failed to power down MIPI bricks: %d\n",
286− err);
287− }
288− }
268+ mutex_lock(&dev->mipi->lock);
289269
290− mutex_unlock(&device->mipi->lock);
270+ if (dev->mipi->usage_count++ == 0)
271+ err = tegra_mipi_power_up(dev->mipi);
272+
273+ mutex_unlock(&dev->mipi->lock);
274+
275+ return err;
291276
292− platform_device_put(device->pdev);
293− kfree(device);
294277 }
295−EXPORT_SYMBOL(tegra_mipi_free);
278+EXPORT_SYMBOL(tegra_mipi_enable);
279+
280+int tegra_mipi_disable(struct tegra_mipi_device *dev)
281+{
282+ int err = 0;
283+
284+ mutex_lock(&dev->mipi->lock);
285+
286+ if (--dev->mipi->usage_count == 0)
287+ err = tegra_mipi_power_down(dev->mipi);
288+
289+ mutex_unlock(&dev->mipi->lock);
290+
291+ return err;
292+
293+}
294+EXPORT_SYMBOL(tegra_mipi_disable);
296295
297296 static int tegra_mipi_wait(struct tegra_mipi *mipi)
298297 {
include/linux/host1x.h+2−0
@@ -304,6 +304,8 @@ struct tegra_mipi_device; · 303 unmodified lines
304304
305305 struct tegra_mipi_device *tegra_mipi_request(struct device *device);
306306 void tegra_mipi_free(struct tegra_mipi_device *device);
307+int tegra_mipi_enable(struct tegra_mipi_device *device);
308+int tegra_mipi_disable(struct tegra_mipi_device *device);
307309 int tegra_mipi_calibrate(struct tegra_mipi_device *device);
308310
309311 #endif