From patchwork Thu Mar 20 15:17:12 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Fuzzey X-Patchwork-Id: 3866781 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 05BE8BF540 for ; Thu, 20 Mar 2014 15:17:54 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 33DAF201F4 for ; Thu, 20 Mar 2014 15:17:53 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B4342201E7 for ; Thu, 20 Mar 2014 15:17:51 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WQej6-0001yG-92; Thu, 20 Mar 2014 15:17:48 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1WQej3-0004lW-KL; Thu, 20 Mar 2014 15:17:45 +0000 Received: from mta1.parkeon.com ([91.121.43.66]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WQej0-0004k4-LX for linux-arm-kernel@lists.infradead.org; Thu, 20 Mar 2014 15:17:43 +0000 Received: from ip71.parkeon.com ([213.152.31.71] helo=mta2.parkeon.com) by mta1.parkeon.com with esmtp (Exim 4.76) (envelope-from ) id 1WQeiW-0005SJ-Gf; Thu, 20 Mar 2014 16:17:12 +0100 Received: from mail.besancon.parkeon.com ([10.32.16.23]) by mta2.parkeon.com with esmtp (Exim 4.77) (envelope-from ) id 1WQeiU-0003la-FO; Thu, 20 Mar 2014 16:17:10 +0100 Received: from [10.32.51.212] (port=59406 helo=[127.0.0.1]) by mail.besancon.parkeon.com with esmtp (Exim 4.71) (envelope-from ) id 1WQeiW-0007Le-CS; Thu, 20 Mar 2014 16:17:12 +0100 Subject: [RFC PATCH] staging: imx-drm: add suspend / resume To: devel@driverdev.osuosl.org, Greg Kroah-Hartman , Sascha Hauer , linux-arm-kernel@lists.infradead.org From: Martin Fuzzey Date: Thu, 20 Mar 2014 16:17:12 +0100 Message-ID: <20140320151712.22089.59230.stgit@localhost> User-Agent: StGit/0.16 MIME-Version: 1.0 X-Virus-Scanned: by ClamAV at mta2.parkeon.com X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140320_111742_801502_D6179872 X-CRM114-Status: GOOD ( 13.15 ) X-Spam-Score: -1.9 (-) Cc: Fabio Estevam X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org 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 Currently i.MX53 boards with the imx-drm display driver active fail an intensive suspend to ram / resume test. After around 5 - 50 cycles it is no longer possible to resume the board. The culprit is the imx-drm driver which does not stop DMA before suspending. Removing the driver "fixes" the problem. This patch provides a minimal suspend / resume implementation enabling the intensive test to work (500 cycles ok). I am only sending this as RFC for the moment since I don't really know the hardware or driver code well enough to be sure this is the "right" way of doing it. Signed-off-by: Martin Fuzzey --- drivers/staging/imx-drm/ipu-v3/ipu-common.c | 47 +++++++++++++++++++++++++++ drivers/staging/imx-drm/ipu-v3/ipu-prv.h | 1 + 2 files changed, 48 insertions(+) diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c index 97ca692..484a90a 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c @@ -692,6 +692,8 @@ int ipu_idmac_enable_channel(struct ipuv3_channel *channel) val |= idma_mask(channel->num); ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num)); + channel->enabled = true; + spin_unlock_irqrestore(&ipu->lock, flags); return 0; @@ -750,6 +752,8 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel) val &= ~idma_mask(channel->num); ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num)); + channel->enabled = false; + spin_unlock_irqrestore(&ipu->lock, flags); return 0; @@ -1245,10 +1249,53 @@ static int ipu_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP + +static int ipu_suspend(struct device *dev) +{ + struct ipu_soc *ipu = dev_get_drvdata(dev); + struct ipuv3_channel *channel; + int i; + + channel = ipu->channel; + for (i = 0; i < ARRAY_SIZE(ipu->channel); i++, channel++) { + channel->suspended = false; + if (channel->enabled) { + if (ipu_idmac_wait_busy(channel, 50)) + dev_warn(dev, + "%s: Timeout channel %d idle\n", + __func__, i); + ipu_idmac_disable_channel(channel); + channel->suspended = true; + } + } + return 0; +} + +static int ipu_resume(struct device *dev) +{ + struct ipu_soc *ipu = dev_get_drvdata(dev); + struct ipuv3_channel *channel; + int i; + + channel = ipu->channel; + for (i = 0; i < ARRAY_SIZE(ipu->channel); i++, channel++) { + if (channel->suspended) { + ipu_idmac_enable_channel(channel); + channel->suspended = false; + } + } + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(ipu_pm_ops, ipu_suspend, ipu_resume); + static struct platform_driver imx_ipu_driver = { .driver = { .name = "imx-ipuv3", .of_match_table = imx_ipu_dt_ids, + .pm = &ipu_pm_ops, }, .probe = ipu_probe, .remove = ipu_remove, diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h index 4df0050..233749a 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h +++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h @@ -144,6 +144,7 @@ struct ipuv3_channel { bool enabled; bool busy; + bool suspended; struct ipu_soc *ipu; };