From patchwork Mon Dec 8 06:40:50 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Zhang X-Patchwork-Id: 5460781 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 255C89F1D4 for ; Tue, 9 Dec 2014 08:21:46 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2E2432018E for ; Tue, 9 Dec 2014 08:21:45 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id E6B5120160 for ; Tue, 9 Dec 2014 08:21:42 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id AF0D06FA68; Tue, 9 Dec 2014 00:21:39 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from hqemgate15.nvidia.com (hqemgate15.nvidia.com [216.228.121.64]) by gabe.freedesktop.org (Postfix) with ESMTP id B26216E2C7 for ; Sun, 7 Dec 2014 22:41:20 -0800 (PST) Received: from hqnvupgp07.nvidia.com (Not Verified[216.228.121.13]) by hqemgate15.nvidia.com id ; Sun, 07 Dec 2014 22:40:30 -0800 Received: from HQMAIL101.nvidia.com ([172.20.12.94]) by hqnvupgp07.nvidia.com (PGP Universal service); Sun, 07 Dec 2014 22:38:18 -0800 X-PGP-Universal: processed; by hqnvupgp07.nvidia.com on Sun, 07 Dec 2014 22:38:18 -0800 Received: from HQPUB101.nvidia.com (172.20.187.14) by HQMAIL101.nvidia.com (172.20.187.10) with Microsoft SMTP Server (TLS) id 15.0.847.32; Mon, 8 Dec 2014 06:41:18 +0000 Received: from hkemhub02.nvidia.com (10.18.67.13) by HQPUB101.nvidia.com (172.20.187.14) with Microsoft SMTP Server (TLS) id 15.0.847.32; Mon, 8 Dec 2014 06:40:55 +0000 Received: from markz-hp6200.nvidia.com (10.18.67.6) by hkemhub02.nvidia.com (10.18.67.13) with Microsoft SMTP Server (TLS) id 8.3.342.0; Mon, 8 Dec 2014 14:40:52 +0800 From: Mark Zhang To: , , , , Subject: [PATCH] drm/tegra: dsi: Add suspend/resume support Date: Mon, 8 Dec 2014 14:40:50 +0800 Message-ID: <1418020850-7664-1-git-send-email-markz@nvidia.com> X-Mailer: git-send-email 1.8.1.5 X-NVConfidentiality: public MIME-Version: 1.0 X-Mailman-Approved-At: Tue, 09 Dec 2014 00:21:39 -0800 Cc: linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Mark Zhang X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds the suspend/resume support for Tegra drm driver by calling the corresponding DPMS functions. Signed-off-by: Mark Zhang --- Hi, This patch hooks DSI driver's suspend/resume to implement the whole display system's suspend/resume. I know this is a super ugly way, but as we all know, Tegra DRM driver doesn't have a dedicate drm device so honestly I didn't find a better way to do that. Thanks, Mark drivers/gpu/drm/tegra/dsi.c | 96 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 90 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 33f67fd601c6..25cd0d93f392 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -61,6 +61,9 @@ struct tegra_dsi { struct tegra_dsi *slave; }; +static int tegra_dsi_pad_calibrate(struct tegra_dsi *); +static int tegra_dsi_ganged_setup(struct tegra_dsi *dsi); + static inline struct tegra_dsi * host1x_client_to_dsi(struct host1x_client *client) { @@ -805,6 +808,20 @@ static int tegra_output_dsi_setup_clock(struct tegra_output *output, lanes = tegra_dsi_get_lanes(dsi); + err = tegra_dsi_pad_calibrate(dsi); + if (err < 0) { + dev_err(dsi->dev, "MIPI calibration failed: %d\n", err); + return err; + } + if (dsi->slave) { + err = tegra_dsi_pad_calibrate(dsi->slave); + if (err < 0) { + dev_err(dsi->slave->dev, + "MIPI calibration failed: %d\n", err); + return err; + } + } + err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); if (err < 0) return err; @@ -833,6 +850,13 @@ static int tegra_output_dsi_setup_clock(struct tegra_output *output, dev_err(dsi->dev, "failed to set parent clock: %d\n", err); return err; } + if (dsi->slave) { + err = tegra_dsi_ganged_setup(dsi); + if (err < 0) { + dev_err(dsi->dev, "DSI ganged setup failed: %d\n", err); + return err; + } + } err = clk_set_rate(dsi->clk_parent, plld); if (err < 0) { @@ -1470,12 +1494,6 @@ static int tegra_dsi_probe(struct platform_device *pdev) goto disable_vdd; } - err = tegra_dsi_pad_calibrate(dsi); - if (err < 0) { - dev_err(dsi->dev, "MIPI calibration failed: %d\n", err); - goto mipi_free; - } - dsi->host.ops = &tegra_dsi_host_ops; dsi->host.dev = &pdev->dev; @@ -1544,6 +1562,67 @@ static int tegra_dsi_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int tegra_dsi_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct tegra_dsi *dsi = platform_get_drvdata(pdev); + struct tegra_drm *tegra = dev_get_drvdata(dsi->client.parent); + struct drm_connector *connector; + + if (dsi->master) { + regulator_disable(dsi->vdd); + return 0; + } + + drm_modeset_lock_all(tegra->drm); + list_for_each_entry(connector, &tegra->drm->mode_config.connector_list, + head) { + int old_dpms = connector->dpms; + + if (connector->funcs->dpms) + connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF); + + /* Set the old mode back to the connector for resume */ + connector->dpms = old_dpms; + } + drm_modeset_unlock_all(tegra->drm); + + regulator_disable(dsi->vdd); + + return 0; +} + +static int tegra_dsi_resume(struct platform_device *pdev) +{ + struct tegra_dsi *dsi = platform_get_drvdata(pdev); + struct tegra_drm *tegra = dev_get_drvdata(dsi->client.parent); + struct drm_connector *connector; + int err = 0; + + err = regulator_enable(dsi->vdd); + if (err < 0) { + dev_err(&pdev->dev, "Enable DSI vdd failed: %d\n", err); + return err; + } + + if (dsi->master) + return 0; + + drm_modeset_lock_all(tegra->drm); + list_for_each_entry(connector, &tegra->drm->mode_config.connector_list, + head) { + if (connector->funcs->dpms) + connector->funcs->dpms(connector, connector->dpms); + } + drm_modeset_unlock_all(tegra->drm); + + drm_helper_resume_force_mode(tegra->drm); + + return 0; +} +#endif + + static const struct of_device_id tegra_dsi_of_match[] = { { .compatible = "nvidia,tegra114-dsi", }, { }, @@ -1557,4 +1636,9 @@ struct platform_driver tegra_dsi_driver = { }, .probe = tegra_dsi_probe, .remove = tegra_dsi_remove, +#ifdef CONFIG_PM + .suspend = tegra_dsi_suspend, + .resume = tegra_dsi_resume, +#endif + };