From patchwork Thu May 9 21:19:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lubomir Rintel X-Patchwork-Id: 10937833 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C0C4D13AD for ; Thu, 9 May 2019 21:19:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B046D28A68 for ; Thu, 9 May 2019 21:19:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A461A28AAC; Thu, 9 May 2019 21:19:46 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2B4F128A68 for ; Thu, 9 May 2019 21:19:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726817AbfEIVTp (ORCPT ); Thu, 9 May 2019 17:19:45 -0400 Received: from shell.v3.sk ([90.176.6.54]:45844 "EHLO shell.v3.sk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726806AbfEIVTp (ORCPT ); Thu, 9 May 2019 17:19:45 -0400 Received: from localhost (localhost [127.0.0.1]) by zimbra.v3.sk (Postfix) with ESMTP id 7E614104024; Thu, 9 May 2019 23:19:42 +0200 (CEST) Received: from shell.v3.sk ([127.0.0.1]) by localhost (zimbra.v3.sk [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id iluzY6wj_yDR; Thu, 9 May 2019 23:19:30 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by zimbra.v3.sk (Postfix) with ESMTP id 53433104026; Thu, 9 May 2019 23:19:23 +0200 (CEST) X-Virus-Scanned: amavisd-new at zimbra.v3.sk Received: from shell.v3.sk ([127.0.0.1]) by localhost (zimbra.v3.sk [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id ekLLkc6jHzlj; Thu, 9 May 2019 23:19:19 +0200 (CEST) Received: from furthur.local (g-server-2.ign.cz [91.219.240.2]) by zimbra.v3.sk (Postfix) with ESMTPSA id 6330C10402B; Thu, 9 May 2019 23:19:18 +0200 (CEST) From: Lubomir Rintel To: linux-pm@vger.kernel.org Cc: "Rafael J. Wysocki" , Kevin Hilman , Ulf Hansson , James Cameron , Michael Turquette , Stephen Boyd , Lubomir Rintel Subject: [PATCH RFC 5/7] clk: mmp2: create a power domain for the GPU core Date: Thu, 9 May 2019 23:19:09 +0200 Message-Id: <20190509211911.17998-6-lkundrak@v3.sk> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190509211911.17998-1-lkundrak@v3.sk> References: <20190509211911.17998-1-lkundrak@v3.sk> MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The power management unit on MMP2 is able to gate clock for the GC860 GPU. There's some special dance required to initialize the unit after the power has been enabled. If not followed, either the GPU's memory interface or the GPU core doesn't work or the SoC just hangs. Once the power has been applied to the GPU block, it doesn't seem possible to turn it off entirely and initialize again. As the data sheet is missing, neither the details about initialization, nor the reason why it can't be reinitialized are understood. The meaning of most bits in the APMU_GPU register are partially described in [1]. [1] http://lists.laptop.org/pipermail/devel/2019-April/039053.html Signed-off-by: Lubomir Rintel --- arch/arm/mach-mmp/Kconfig | 2 + drivers/clk/mmp/clk-of-mmp2.c | 91 +++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig index 94500bed56ab..a0efaefbfc74 100644 --- a/arch/arm/mach-mmp/Kconfig +++ b/arch/arm/mach-mmp/Kconfig @@ -124,6 +124,8 @@ config MACH_MMP2_DT select PINCTRL_SINGLE select ARCH_HAS_RESET_CONTROLLER select CPU_PJ4 + select PM_GENERIC_DOMAINS if PM + select PM_GENERIC_DOMAINS_OF if PM && OF help Include support for Marvell MMP2 based platforms using the device tree. diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index 45f94c89cdc1..7bbf70b2ccd2 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -16,8 +16,11 @@ #include #include #include +#include +#include #include +#include #include "clk.h" #include "reset.h" @@ -58,6 +61,8 @@ struct mmp2_clk_unit { struct mmp_clk_unit unit; + struct genpd_onecell_data pd_data; + struct generic_pm_domain gpu_pm_domain; void __iomem *mpmu_base; void __iomem *apmu_base; void __iomem *apbc_base; @@ -325,6 +330,90 @@ static void mmp2_clk_reset_init(struct device_node *np, mmp_clk_reset_register(np, cells, nr_resets); } +static int mmp2_gpu_pm_domain_power_on(struct generic_pm_domain *genpd) +{ + struct mmp2_clk_unit *pxa_unit = container_of(genpd, + struct mmp2_clk_unit, gpu_pm_domain); + struct mmp_clk_unit *unit = &pxa_unit->unit; + void __iomem *reg = pxa_unit->apmu_base + APMU_GPU; + unsigned long flags = 0; + u32 tmp; + int ret; + + spin_lock_irqsave(&gpu_lock, flags); + + /* Power up the module. */ + tmp = readl(reg); + tmp &= ~0x8700; + tmp |= 0x8600; + writel(tmp, reg); + + ret = clk_prepare_enable(unit->clk_table[MMP2_CLK_GPU_GC]); + if (ret) + return ret; + + ret = clk_prepare_enable(unit->clk_table[MMP2_CLK_GPU_BUS]); + if (ret) { + clk_disable_unprepare(unit->clk_table[MMP2_CLK_GPU_GC]); + return ret; + } + + /* Disable isolation now that clocks are running. */ + tmp = readl(reg); + tmp |= 0x100; + writel(tmp, reg); + udelay(1); + + spin_unlock_irqrestore(&gpu_lock, flags); + + return 0; +} + +static int mmp2_gpu_pm_domain_power_off(struct generic_pm_domain *genpd) +{ + struct mmp2_clk_unit *pxa_unit = container_of(genpd, + struct mmp2_clk_unit, gpu_pm_domain); + struct mmp_clk_unit *unit = &pxa_unit->unit; + void __iomem *reg = pxa_unit->apmu_base + APMU_GPU; + unsigned long flags = 0; + u32 tmp; + + spin_lock_irqsave(&gpu_lock, flags); + + /* + * Re-enable isolation. We must not touch the other bits, + * otherwise the * GPU hangs without a known way to recover. + */ + tmp = readl(reg); + tmp &= ~0x100; + writel(tmp, reg); + udelay(1); + + clk_disable_unprepare(unit->clk_table[MMP2_CLK_GPU_BUS]); + clk_disable_unprepare(unit->clk_table[MMP2_CLK_GPU_GC]); + + spin_unlock_irqrestore(&gpu_lock, flags); + + return 0; +} + +static struct generic_pm_domain *mmp2_pm_onecell_domains[MMP2_NR_POWER_DOMAINS]; + +static void mmp2_pm_domain_init(struct device_node *np, + struct mmp2_clk_unit *pxa_unit) +{ + pm_genpd_init(&pxa_unit->gpu_pm_domain, NULL, true); + pxa_unit->gpu_pm_domain.name = "GPU"; + pxa_unit->gpu_pm_domain.power_on = mmp2_gpu_pm_domain_power_on; + pxa_unit->gpu_pm_domain.power_off = mmp2_gpu_pm_domain_power_off; + mmp2_pm_onecell_domains[MMP2_POWER_DOMAIN_GPU] + = &pxa_unit->gpu_pm_domain; + + pxa_unit->pd_data.domains = mmp2_pm_onecell_domains; + pxa_unit->pd_data.num_domains = ARRAY_SIZE(mmp2_pm_onecell_domains); + of_genpd_add_provider_onecell(np, &pxa_unit->pd_data); +} + static void __init mmp2_clk_init(struct device_node *np) { struct mmp2_clk_unit *pxa_unit; @@ -351,6 +440,8 @@ static void __init mmp2_clk_init(struct device_node *np) goto unmap_apmu_region; } + mmp2_pm_domain_init(np, pxa_unit); + mmp_clk_init(np, &pxa_unit->unit, MMP2_NR_CLKS); mmp2_pll_init(pxa_unit);