From patchwork Fri Aug 2 13:23:19 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartlomiej Zolnierkiewicz X-Patchwork-Id: 2837891 Return-Path: X-Original-To: patchwork-linux-samsung-soc@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 4F82B9F492 for ; Fri, 2 Aug 2013 13:23:48 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B4C772045E for ; Fri, 2 Aug 2013 13:23:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id BABB720453 for ; Fri, 2 Aug 2013 13:23:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751560Ab3HBNXo (ORCPT ); Fri, 2 Aug 2013 09:23:44 -0400 Received: from mailout2.samsung.com ([203.254.224.25]:42482 "EHLO mailout2.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751407Ab3HBNXm (ORCPT ); Fri, 2 Aug 2013 09:23:42 -0400 Received: from epcpsbgm2.samsung.com (epcpsbgm2 [203.254.230.27]) by mailout2.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MQW00K9ZNVGU6A0@mailout2.samsung.com>; Fri, 02 Aug 2013 22:23:41 +0900 (KST) X-AuditID: cbfee61b-b7efe6d000007b11-e6-51fbb2dc1b54 Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id 07.FF.31505.CD2BBF15; Fri, 02 Aug 2013 22:23:40 +0900 (KST) Received: from amdc1032.localnet ([106.116.147.136]) by mmp1.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MQW008DDNVEMU50@mmp1.samsung.com>; Fri, 02 Aug 2013 22:23:40 +0900 (KST) From: Bartlomiej Zolnierkiewicz To: Kukjin Kim Cc: Myungjoo Ham , Tomasz Figa , Stephen Warren , linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-pm@vger.kernel.org, devicetree@vger.kernel.org Subject: [PATCH] ARM: EXYNOS: add power domains support for EXYNOS5440 Date: Fri, 02 Aug 2013 15:23:19 +0200 Message-id: <2729097.X0eAsuYF97@amdc1032> User-Agent: KMail/4.8.4 (Linux/3.2.0-45-generic; KDE/4.8.5; i686; ; ) MIME-version: 1.0 Content-transfer-encoding: 7Bit Content-type: text/plain; charset=us-ascii X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrILMWRmVeSWpSXmKPExsVy+t9jAd07m34HGixdYW4x/8g5VoveBVfZ LDY9vsZq8bn3CKPFjPP7mCxuN65gs3h1sI3FYv2M1ywOHB6bl9R79G1ZxejxeZOcx8a5oQEs UVw2Kak5mWWpRfp2CVwZnw7eZCuYHlJxqae4gXG9cxcjJ4eEgInE72NrGCFsMYkL99azdTFy cQgJLGKUOLWyA8ppYZL4uuMVE0gVm4CVxMT2VWAdIgJqEj2LtzKCFDEL/GKUePZvP2sXIweH sICbRE8XC0gNi4CqRP/SLWwgNq+ApsT1hcvB4qICrhLnFv1ggYgLSvyYfA/MZhaQl9i3fyor hK0lsX7ncaYJjHyzkJTNQlI2C0nZAkbmVYyiqQXJBcVJ6blGesWJucWleel6yfm5mxjBAftM egfjqgaLQ4wCHIxKPLwPMn8FCrEmlhVX5h5ilOBgVhLh/TMbKMSbklhZlVqUH19UmpNafIhR moNFSZz3YKt1oJBAemJJanZqakFqEUyWiYNTqoHRivPRLM+4i+rVZnr6eTN8624k5T3JV7wZ 8zfEddt+nsK1t77qxBfz3SnUcnszXcS9XSn72v+kSzlzw7cs8HrUxyzbksbZ/Sbf4f2euHsJ daWX87ezf43Y5lZlvbhSNOiD/MULnmLad5P55hU9Y7wZ5L0667DAf6btWp2v56nPfvUnvvX2 rjVKLMUZiYZazEXFiQCpk4JhVAIAAA== Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Spam-Status: No, score=-8.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, 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 On EXYNOS5440 power domains are handled in a different way than on the previous EXYNOS SoCs. Add support for them to EXYNOS pm_domains driver. Then add device tree nodes for PCIe (controlling power for PCIe host controller) and Conn2 (controlling power for Ethernet, SATA and USB controllers) power domains to exynos5440.dtsi. Currently if runtime Power Management is enabled and the driver for devices under power domain is disabled then the power domain will be disabled by EXYNOS pm_domains driver. To make more active use of power domains (dynamically enable and disabled them as needed) it is required to add runtime PM support to pci-exynos, stmmac, ahci_platform, ohci-exynos and ehci-s5p drivers (to be done later). Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Myungjoo Ham Cc: Tomasz Figa Cc: Stephen Warren --- Documentation/devicetree/bindings/arm/exynos/power_domain.txt | 33 ++ arch/arm/boot/dts/exynos5440.dtsi | 23 + arch/arm/mach-exynos/Kconfig | 1 arch/arm/mach-exynos/common.c | 4 arch/arm/mach-exynos/pm_domains.c | 138 +++++++++- 5 files changed, 190 insertions(+), 9 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Index: b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt =================================================================== --- a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt 2013-08-02 14:45:53.551392396 +0200 +++ b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt 2013-08-02 14:46:29.799391845 +0200 @@ -5,20 +5,47 @@ to gate power to one or more peripherals Required Properties: - compatible: should be one of the following. - * samsung,exynos4210-pd - for exynos4210 type power domain. + * samsung,exynos4210-pd - for Exynos4210 type power domain. + * samsung,exynos5440-pd - for Exynos5440 type power domain. - reg: physical base address of the controller and length of memory mapped - region. + region (Exynos4210 type power domain) or bit offset in the control + register (Exynos5440 type power domain). + +Additional parent node must be created for Exynos5440 power domains with +the following required properties: +- compatible: samsung,exynos5440-power-domains, simple-bus +- reg: physical base address of the XMU controller and length of memory + mapped region Node of a device using power domains must have a samsung,power-domain property defined with a phandle to respective power domain. -Example: +Example for Exynos4210 compatible power domain: lcd0: power-domain-lcd0 { compatible = "samsung,exynos4210-pd"; reg = <0x10023C00 0x10>; }; +Example for Exynos5440 compatible power domains: + + power-domains@00160000 { + compatible = "samsung,exynos5440-power-domains", "simple-bus"; + reg = <0x00160000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + pd_pcie: pcie-power-domain@6 { + compatible = "samsung,exynos5440-pd"; + reg = <6>; + }; + + pd_conn2: conn2-power-domain@7 { + compatible = "samsung,exynos5440-pd"; + reg = <7>; + }; + }; + Example of the node using power domain: node { Index: b/arch/arm/boot/dts/exynos5440.dtsi =================================================================== --- a/arch/arm/boot/dts/exynos5440.dtsi 2013-08-02 14:45:53.599392397 +0200 +++ b/arch/arm/boot/dts/exynos5440.dtsi 2013-08-02 14:46:29.815391842 +0200 @@ -29,6 +29,23 @@ #clock-cells = <1>; }; + power-domains@00160000 { + compatible = "samsung,exynos5440-power-domains", "simple-bus"; + reg = <0x00160000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + pd_pcie: pcie-power-domain@6 { + compatible = "samsung,exynos5440-pd"; + reg = <6>; + }; + + pd_conn2: conn2-power-domain@7 { + compatible = "samsung,exynos5440-pd"; + reg = <7>; + }; + }; + gic:interrupt-controller@2E0000 { compatible = "arm,cortex-a15-gic"; #interrupt-cells = <3>; @@ -192,6 +209,7 @@ phy-mode = "sgmii"; clocks = <&clock 25>; clock-names = "stmmaceth"; + samsung,power-domain = <&pd_conn2>; }; amba { @@ -240,6 +258,7 @@ interrupts = <0 30 0>; clocks = <&clock 23>; clock-names = "sata"; + samsung,power-domain = <&pd_conn2>; }; ohci@220000 { @@ -248,6 +267,7 @@ interrupts = <0 29 0>; clocks = <&clock 24>; clock-names = "usbhost"; + samsung,power-domain = <&pd_conn2>; }; ehci@221000 { @@ -256,6 +276,7 @@ interrupts = <0 29 0>; clocks = <&clock 24>; clock-names = "usbhost"; + samsung,power-domain = <&pd_conn2>; }; pcie@290000 { @@ -275,6 +296,7 @@ #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0x0 0 &gic 53>; + samsung,power-domain = <&pd_pcie>; }; pcie@2a0000 { @@ -294,5 +316,6 @@ #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0x0 0 &gic 56>; + samsung,power-domain = <&pd_pcie>; }; }; Index: b/arch/arm/mach-exynos/Kconfig =================================================================== --- a/arch/arm/mach-exynos/Kconfig 2013-08-02 14:45:53.563392396 +0200 +++ b/arch/arm/mach-exynos/Kconfig 2013-08-02 14:46:29.815391842 +0200 @@ -104,6 +104,7 @@ config SOC_EXYNOS5440 select MIGHT_HAVE_PCI select PCI_DOMAINS if PCI select PINCTRL_EXYNOS5440 + select PM_GENERIC_DOMAINS if PM select PM_OPP help Enable EXYNOS5440 SoC support Index: b/arch/arm/mach-exynos/common.c =================================================================== --- a/arch/arm/mach-exynos/common.c 2013-08-02 14:45:53.583392397 +0200 +++ b/arch/arm/mach-exynos/common.c 2013-08-02 14:46:29.815391842 +0200 @@ -296,10 +296,6 @@ void exynos5_restart(enum reboot_mode mo void __init exynos_init_late(void) { - if (of_machine_is_compatible("samsung,exynos5440")) - /* to be supported later */ - return; - exynos_pm_late_initcall(); } Index: b/arch/arm/mach-exynos/pm_domains.c =================================================================== --- a/arch/arm/mach-exynos/pm_domains.c 2013-08-02 14:45:53.571392397 +0200 +++ b/arch/arm/mach-exynos/pm_domains.c 2013-08-02 14:47:36.471390825 +0200 @@ -24,12 +24,14 @@ #include #include +#include /* * Exynos specific wrapper around the generic power domain */ struct exynos_pm_domain { void __iomem *base; + unsigned int bit_offset; char const *name; bool is_off; struct generic_pm_domain pd; @@ -74,6 +76,75 @@ static int exynos_pd_power_off(struct ge return exynos_pd_power(domain, false); } +#define EXYNOS5440_PMU_STATUS 0x00BC +#define EXYNOS5440_PMU_CTRL 0x00C0 + +static int exynos5440_check_status(struct exynos_pm_domain *pd, u32 *pwr) +{ + u32 timeout = 10; /* Wait max 1ms */ + int ret = 0; + + do { + *pwr = readl(pd->base + EXYNOS5440_PMU_STATUS); + if ((*pwr & BIT(pd->bit_offset + 16)) == 0) + break; + if (!timeout) { + pr_err("%s: power domain %s status read failed\n", + __func__, pd->name); + ret = -ETIMEDOUT; + break; + } + timeout--; + usleep_range(80, 100); + } while (1); + + return ret; +} + +static int exynos5440_pd_power(struct generic_pm_domain *domain, + bool power_on) +{ + struct exynos_pm_domain *pd = + container_of(domain, struct exynos_pm_domain, pd); + void __iomem *base = pd->base; + unsigned int bit_offset = pd->bit_offset; + u32 pwr; + int ret; + + pwr = readl(base + EXYNOS5440_PMU_CTRL); + if (power_on) + pwr |= BIT(bit_offset); + else + pwr |= BIT(bit_offset + 16); + writel(pwr, base + EXYNOS5440_PMU_CTRL); + + ret = exynos5440_check_status(pd, &pwr); + if (ret) + goto err; + + if ((power_on && (pwr & BIT(bit_offset)) == 0) || + (!power_on && (pwr & BIT(bit_offset)))) { + ret = -EIO; + goto err; + } + + return 0; +err: + pr_err("Power domain %s %s failed (error=%d)\n", + domain->name, power_on ? "enable" : "disable", ret); + return ret; +} + +static int exynos5440_pd_power_on(struct generic_pm_domain *domain) +{ + return exynos5440_pd_power(domain, true); +} + +static int exynos5440_pd_power_off(struct generic_pm_domain *domain) +{ + return exynos5440_pd_power(domain, false); +} + static void exynos_add_device_to_domain(struct exynos_pm_domain *pd, struct device *dev) { @@ -146,7 +217,7 @@ static struct notifier_block platform_nb .notifier_call = exynos_pm_notifier_call, }; -static __init int exynos4_pm_init_power_domain(void) +static __init int exynos4210_pm_init_power_domain(void) { struct platform_device *pdev; struct device_node *np; @@ -182,7 +253,70 @@ static __init int exynos4_pm_init_power_ return 0; } -arch_initcall(exynos4_pm_init_power_domain); + +static __init int exynos5440_pm_init_power_domain(void) +{ + struct device_node *np, *node = NULL; + void __iomem *reg_base; + + np = of_find_compatible_node(NULL, NULL, + "samsung,exynos5440-power-domains"); + if (!np) + return 0; + + reg_base = of_iomap(np, 0); + + for_each_child_of_node(np, node) { + struct platform_device *pdev; + struct exynos_pm_domain *pd; + u32 pwr; + int ret, on; + + pdev = of_find_device_by_node(node); + if (pdev == NULL) { + pr_err("%s: failed to get platform device for domain\n", + __func__); + continue; + } + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) { + pr_err("%s: failed to allocate memory for domain\n", + __func__); + return -ENOMEM; + } + + pd->pd.name = kstrdup(node->name, GFP_KERNEL); + pd->name = pd->pd.name; + pd->base = reg_base; + if (of_property_read_u32(node, "reg", &pd->bit_offset)) + pr_err("%s: bit offset not specified for domain %s\n", + __func__, pd->name); + pd->pd.power_off = exynos5440_pd_power_off; + pd->pd.power_on = exynos5440_pd_power_on; + pd->pd.of_node = node; + + platform_set_drvdata(pdev, pd); + + ret = exynos5440_check_status(pd, &pwr); + on = ret ? 0 : !!(pwr & BIT(pd->bit_offset)); + + pm_genpd_init(&pd->pd, NULL, !on); + } + + bus_register_notifier(&platform_bus_type, &platform_nb); + + return 0; +} + +static __init int exynos_pm_init_power_domain(void) +{ + if (soc_is_exynos5440()) + return exynos5440_pm_init_power_domain(); + else + return exynos4210_pm_init_power_domain(); +} +arch_initcall(exynos_pm_init_power_domain); int __init exynos_pm_late_initcall(void) {