From patchwork Fri Mar 6 17:09:52 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ulrich Hecht X-Patchwork-Id: 5956661 X-Patchwork-Delegate: horms@verge.net.au Return-Path: X-Original-To: patchwork-linux-sh@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 112B3BF6C3 for ; Fri, 6 Mar 2015 17:10:35 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E0AC72038D for ; Fri, 6 Mar 2015 17:10:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 908BB2037E for ; Fri, 6 Mar 2015 17:10:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932259AbbCFRK1 (ORCPT ); Fri, 6 Mar 2015 12:10:27 -0500 Received: from mail-wi0-f177.google.com ([209.85.212.177]:45464 "EHLO mail-wi0-f177.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932255AbbCFRK0 (ORCPT ); Fri, 6 Mar 2015 12:10:26 -0500 Received: by wibbs8 with SMTP id bs8so5123768wib.4 for ; Fri, 06 Mar 2015 09:10:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=wOHeYv91M3EYf3GQ2gMMOXnWjCuxxgwtLsr5DomCUHQ=; b=mkB8WEYlBcxy12zaLFdXniHLZJswYq+XNCYIZLGBSR5F28eiesMJy3HzYuEX+LXMSF Lh8EeodjSqEATsv662+hiNDwRfqOLyvxIAODaE7xGGq/H4Bo9gV4uiBpXarZgYz6O/Qa q2/VOmF4/Lfi2u7GTgIj9SWHwfhBB0yvAJ1WPp3s0uIKI4WYuhLHlD80DgVnNGxYxYK2 BSZ3CHD1Qlojci2juXjSXAPQKgfuAsnVfm63wreCk4yIUqUqrI7KawX2hCWRm6DogMG8 F2S4IaHi6dPAyHkpT3IMdetsBSIKlqR4udTCECkuhEdl+GbMoOc60MSfTKBaF+JwOao+ qrcw== X-Received: by 10.180.75.233 with SMTP id f9mr6235425wiw.5.1425661825107; Fri, 06 Mar 2015 09:10:25 -0800 (PST) Received: from groucho.site (ipbcc0217c.dynamic.kabel-deutschland.de. [188.192.33.124]) by mx.google.com with ESMTPSA id i10sm14194969wja.40.2015.03.06.09.10.22 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 06 Mar 2015 09:10:23 -0800 (PST) From: Ulrich Hecht To: horms@verge.net.au, linux-sh@vger.kernel.org Cc: magnus.damm@gmail.com, hisashi.nakamura.ak@renesas.com, kuninori.morimoto.gx@renesas.com, Ulrich Hecht , Khiem Nguyen , Kouei Abe Subject: [PATCH 05/11] ARM: shmobile: r8a7793: add power management support Date: Fri, 6 Mar 2015 18:09:52 +0100 Message-Id: <1425661798-10487-6-git-send-email-ulrich.hecht+renesas@gmail.com> X-Mailer: git-send-email 2.2.2 In-Reply-To: <1425661798-10487-1-git-send-email-ulrich.hecht+renesas@gmail.com> References: <1425661798-10487-1-git-send-email-ulrich.hecht+renesas@gmail.com> Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham 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 Not used yet because it depends on SMP. Signed-off-by: Hisashi Nakamura Signed-off-by: Khiem Nguyen Signed-off-by: Kouei Abe [uli: moved reset handling from SMP code, minor adjustments] Signed-off-by: Ulrich Hecht --- arch/arm/mach-shmobile/Makefile | 2 +- arch/arm/mach-shmobile/pm-r8a7793.c | 273 ++++++++++++++++++++++++++++++++++++ arch/arm/mach-shmobile/r8a7793.h | 6 + 3 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-shmobile/pm-r8a7793.c create mode 100644 arch/arm/mach-shmobile/r8a7793.h diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 399342e..a104a24 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_ARCH_R8A7778) += setup-r8a7778.o obj-$(CONFIG_ARCH_R8A7779) += setup-r8a7779.o pm-r8a7779.o obj-$(CONFIG_ARCH_R8A7790) += setup-r8a7790.o pm-r8a7790.o obj-$(CONFIG_ARCH_R8A7791) += setup-r8a7791.o pm-r8a7791.o -obj-$(CONFIG_ARCH_R8A7793) += setup-r8a7793.o +obj-$(CONFIG_ARCH_R8A7793) += setup-r8a7793.o pm-r8a7793.o obj-$(CONFIG_ARCH_R8A7794) += setup-r8a7794.o obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o obj-$(CONFIG_ARCH_R7S72100) += setup-r7s72100.o diff --git a/arch/arm/mach-shmobile/pm-r8a7793.c b/arch/arm/mach-shmobile/pm-r8a7793.c new file mode 100644 index 0000000..a59ac8d --- /dev/null +++ b/arch/arm/mach-shmobile/pm-r8a7793.c @@ -0,0 +1,273 @@ +/* + * r8a7793 Power management support + * + * Copyright (C) 2014 Renesas Electronics Corporation + * Copyright (C) 2015 Ulrich Hecht + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "pm-rcar.h" +#include "r8a7793.h" + +#define RST 0xe6160000 +#define CA15BAR 0x0020 +#define CA15RESCNT 0x0040 +#define RAM 0xe63c0000 + +/* SYSC */ +#define SYSCIER 0x0c +#define SYSCIMR 0x10 + +struct r8a7793_pm_domain { + struct generic_pm_domain genpd; + struct rcar_sysc_ch ch; +}; + +static inline struct rcar_sysc_ch *to_r8a7793_ch(struct generic_pm_domain *d) +{ + return &container_of(d, struct r8a7793_pm_domain, genpd)->ch; +} + +#if defined(CONFIG_PM) || defined(CONFIG_SMP) + +static void __init r8a7793_sysc_init(void) +{ + void __iomem *base = rcar_sysc_init(0xe6180000); + + /* enable all interrupt sources, but do not use interrupt handler */ + iowrite32(0x0131000e, base + SYSCIER); + iowrite32(0, base + SYSCIMR); +} + +#else /* CONFIG_PM || CONFIG_SMP */ + +static inline void r8a7793_sysc_init(void) {} + +#endif /* CONFIG_PM || CONFIG_SMP */ + +#ifdef CONFIG_PM + +#define CPG_BASE 0xe6150000 +#define CPG_LEN 0x1000 + +/* Software Reset */ +#define SRCR0 0x00a0 +#define SRCR1 0x00a8 +#define SRCR2 0x00b0 +#define SRCR3 0x00b8 +#define SRCR4 0x00bc +#define SRCR5 0x00c4 +#define SRCR6 0x01c8 +#define SRCR7 0x01cc +#define SRCR8 0x0920 +#define SRCR9 0x0924 +#define SRCR10 0x0928 +#define SRCR11 0x092c +#define SRSTCLR0 0x0940 +#define SRSTCLR1 0x0944 +#define SRSTCLR2 0x0948 +#define SRSTCLR3 0x094c +#define SRSTCLR4 0x0950 +#define SRSTCLR5 0x0954 +#define SRSTCLR6 0x0958 +#define SRSTCLR7 0x095c +#define SRSTCLR8 0x0960 +#define SRSTCLR9 0x0964 +#define SRSTCLR10 0x0968 +#define SRSTCLR11 0x096c + +#define SRST_REG(n) { .srcr = SRCR##n, .srstclr = SRSTCLR##n, } + +static struct software_reset_reg { + u16 srcr; + u16 srstclr; +} r8a7793_reset_regs[] = { + [0] = SRST_REG(0), + [1] = SRST_REG(1), + [2] = SRST_REG(2), + [3] = SRST_REG(3), + [4] = SRST_REG(4), + [5] = SRST_REG(5), + [6] = SRST_REG(6), + [7] = SRST_REG(7), + [8] = SRST_REG(8), + [9] = SRST_REG(9), + [10] = SRST_REG(10), + [11] = SRST_REG(11), +}; + +static DEFINE_SPINLOCK(r8a7793_reset_lock); + +void r8a7793_module_reset(unsigned int n, u32 bits, int usecs) +{ + void __iomem *cpg_base; + unsigned long flags; + u32 srcr; + + if (n >= ARRAY_SIZE(r8a7793_reset_regs)) { + pr_err("SRCR%u is not available\n", n); + return; + } + + /* give a short delay for at least one RCLK cycle */ + if (usecs <= 0) + usecs = 50; + + cpg_base = ioremap(CPG_BASE, CPG_LEN); + + spin_lock_irqsave(&r8a7793_reset_lock, flags); + srcr = readl_relaxed(cpg_base + r8a7793_reset_regs[n].srcr); + writel_relaxed(srcr | bits, cpg_base + r8a7793_reset_regs[n].srcr); + readl_relaxed(cpg_base + r8a7793_reset_regs[n].srcr); /* sync */ + spin_unlock_irqrestore(&r8a7793_reset_lock, flags); + + udelay(usecs); + + writel_relaxed(bits, cpg_base + r8a7793_reset_regs[n].srstclr); + readl_relaxed(cpg_base + r8a7793_reset_regs[n].srstclr); /* sync */ + + iounmap(cpg_base); +} + +static int pd_power_down(struct generic_pm_domain *genpd) +{ + struct rcar_sysc_ch *r8a7793_ch = to_r8a7793_ch(genpd); + int ret; + + ret = rcar_sysc_power_down(to_r8a7793_ch(genpd)); + + if (r8a7793_ch->chan_offs == 0xc0) { + /* + * Issue software reset to 3DG functional blocks right after + * the SGX power shut-off to avoid a hardware lock-up issue + * triggered when we bring the SGX power up next time. + */ + r8a7793_module_reset(1, BIT(12), 2); /* DVFS */ + r8a7793_module_reset(8, BIT(0), 2); /* CONST */ + } + + return ret; +} + +static int pd_power_up(struct generic_pm_domain *genpd) +{ + return rcar_sysc_power_up(to_r8a7793_ch(genpd)); +} + +static bool pd_active_wakeup(struct device *dev) +{ + return true; +} + +static struct notifier_block platform_nb; + +static void r8a7793_init_pm_domain(struct r8a7793_pm_domain *r8a7793_pd) +{ + struct generic_pm_domain *genpd = &r8a7793_pd->genpd; + + pm_genpd_init(genpd, NULL, true); + genpd->dev_ops.stop = pm_clk_suspend; + genpd->dev_ops.start = pm_clk_resume; + genpd->dev_ops.active_wakeup = pd_active_wakeup; + genpd->power_off = pd_power_down; + genpd->power_on = pd_power_up; + + bus_register_notifier(&platform_bus_type, &platform_nb); +} + +static struct r8a7793_pm_domain r8a7793_pm_domains[] = { + { + .genpd.name = "pvrsrvkm", + .ch = { + .chan_offs = 0xc0, /* PWRSR2 .. PWRER2 */ + .isr_bit = 20, /* SGX */ + }, + }, +}; + +void __init r8a7793_init_pm_domains(void) +{ + int j; + + for (j = 0; j < ARRAY_SIZE(r8a7793_pm_domains); j++) + r8a7793_init_pm_domain(&r8a7793_pm_domains[j]); +} + +static int r8a7793_pm_notifier_call(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct device *dev = data; + struct r8a7793_pm_domain *pd; + int j; + + switch (event) { + case BUS_NOTIFY_BIND_DRIVER: + for (j = 0; j < ARRAY_SIZE(r8a7793_pm_domains); j++) { + pd = &r8a7793_pm_domains[j]; + if (!strcmp(pd->genpd.name, dev_name(dev))) { + pm_genpd_add_device(&pd->genpd, dev); + if (pm_clk_no_clocks(dev)) + pm_clk_add(dev, NULL); + } + } + break; + + case BUS_NOTIFY_UNBOUND_DRIVER: + for (j = 0; j < ARRAY_SIZE(r8a7793_pm_domains); j++) { + pd = &r8a7793_pm_domains[j]; + if (!strcmp(pd->genpd.name, dev_name(dev))) + pm_genpd_remove_device(&pd->genpd, dev); + + } + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block platform_nb = { + .notifier_call = r8a7793_pm_notifier_call, +}; + +#endif /* CONFIG_PM */ + +void __init r8a7793_pm_init(void) +{ + void __iomem *p; + u32 bar; + static int once; + + if (once++) + return; + + /* RAM for jump stub, because BAR requires 256KB aligned address */ + p = ioremap_nocache(RAM, shmobile_boot_size); + memcpy_toio(p, shmobile_boot_vector, shmobile_boot_size); + iounmap(p); + + /* setup reset vectors */ + p = ioremap_nocache(RST, 0x63); + bar = (RAM >> 8) & 0xfffffc00; + writel_relaxed(bar, p + CA15BAR); + writel_relaxed(bar | 0x10, p + CA15BAR); + + /* enable clocks to all CPUs */ + writel_relaxed((readl_relaxed(p + CA15RESCNT) & ~0x0f) | 0xa5a50000, + p + CA15RESCNT); + iounmap(p); + + r8a7793_sysc_init(); + shmobile_smp_apmu_suspend_init(); +} diff --git a/arch/arm/mach-shmobile/r8a7793.h b/arch/arm/mach-shmobile/r8a7793.h new file mode 100644 index 0000000..78894c3 --- /dev/null +++ b/arch/arm/mach-shmobile/r8a7793.h @@ -0,0 +1,6 @@ +#ifndef __ASM_R8A7793_H__ +#define __ASM_R8A7793_H__ + +void r8a7793_pm_init(void); + +#endif /* __ASM_R8A7793_H__ */