From patchwork Mon Aug 8 10:05:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wenyou Yang X-Patchwork-Id: 9267681 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id AEE36607D6 for ; Mon, 8 Aug 2016 10:20:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9DA4D26E8A for ; Mon, 8 Aug 2016 10:20:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9250027DCE; Mon, 8 Aug 2016 10:20:27 +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=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 10F6C26E8A for ; Mon, 8 Aug 2016 10:20:27 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bWheC-00076H-Pl; Mon, 08 Aug 2016 10:19:04 +0000 Received: from eusmtp01.atmel.com ([212.144.249.242]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bWhe0-0006s5-R8 for linux-arm-kernel@lists.infradead.org; Mon, 08 Aug 2016 10:18:58 +0000 Received: from apsmtp01.atmel.com (10.168.254.30) by eusmtp01.atmel.com (10.145.145.30) with Microsoft SMTP Server id 14.3.235.1; Mon, 8 Aug 2016 12:18:30 +0200 Received: from shaarm01.corp.atmel.com (10.168.254.13) by apsmtp01.corp.atmel.com (10.168.254.30) with Microsoft SMTP Server id 14.3.235.1; Mon, 8 Aug 2016 18:25:41 +0800 From: Wenyou Yang To: Nicolas Ferre , Alexandre Belloni , Russell King Subject: [PATCH v6 3/6] ARM: at91: pm: Add ULP1 mode support Date: Mon, 8 Aug 2016 18:05:02 +0800 Message-ID: <1470650705-31418-4-git-send-email-wenyou.yang@atmel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1470650705-31418-1-git-send-email-wenyou.yang@atmel.com> References: <1470650705-31418-1-git-send-email-wenyou.yang@atmel.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160808_031853_666792_8C4E2AA5 X-CRM114-Status: GOOD ( 16.57 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, Pawel Moll , Ian Campbell , Mark Brown , linux-kernel@vger.kernel.org, Wenyou Yang , Rob Herring , Kumar Gala , linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP In the ULP1 mode, in order to achieve the lowest power consumption with the system in retention mode and be able to resume on the wake up events, all the clocks are shut off, inclusive the embedded 12MHz RC oscillator, and the number of wake up sources is limited as well. When the wake up event is asserted, the embedded 12MHz RC oscillator restarts automatically. The ULP1 (Ultra Low-power mode 1) is introduced by SAMA5D2. Signed-off-by: Wenyou Yang --- Changes in v6: - Add specific sama5d2_pm_init() for SAMA5D2, which supports ULP1. It is called sama5d2_dt_device_init(). Instead of by reading the PMC version to check if it supports ULP1. - Add comment to describe the platform condition of calling at91_pm_ulp1_mode(). - Update the commit log. Changes in v5: None Changes in v4: None Changes in v3: None Changes in v2: - fix label pm_exit to ulp_exit. arch/arm/mach-at91/generic.h | 2 + arch/arm/mach-at91/pm.c | 18 +++++++- arch/arm/mach-at91/pm.h | 7 +++ arch/arm/mach-at91/pm_suspend.S | 99 +++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-at91/sama5.c | 1 + include/linux/clk/at91_pmc.h | 2 + 6 files changed, 127 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h index 28ca57a..d716164 100644 --- a/arch/arm/mach-at91/generic.h +++ b/arch/arm/mach-at91/generic.h @@ -17,12 +17,14 @@ extern void __init at91sam9260_pm_init(void); extern void __init at91sam9g45_pm_init(void); extern void __init at91sam9x5_pm_init(void); extern void __init sama5_pm_init(void); +extern void __init sama5d2_pm_init(void); #else static inline void __init at91rm9200_pm_init(void) { } static inline void __init at91sam9260_pm_init(void) { } static inline void __init at91sam9g45_pm_init(void) { } static inline void __init at91sam9x5_pm_init(void) { } static inline void __init sama5_pm_init(void) { } +static inline void __init sama5d2_pm_init(void) { } #endif #endif /* _AT91_GENERIC_H */ diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index f062701..dad412f 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -36,6 +36,9 @@ #include "generic.h" #include "pm.h" +#define ULP0_MODE 0x00 +#define ULP1_MODE 0x11 + static void __iomem *pmc; /* @@ -52,6 +55,7 @@ extern void at91_pinctrl_gpio_resume(void); static struct { unsigned long uhp_udp_mask; int memctrl; + u32 ulp_mode; } at91_pm_data; void __iomem *at91_ramc_base[2]; @@ -141,8 +145,11 @@ static void at91_pm_suspend(suspend_state_t state) { unsigned int pm_data = at91_pm_data.memctrl; - pm_data |= (state == PM_SUSPEND_MEM) ? - AT91_PM_MODE(AT91_PM_SLOW_CLOCK) : 0; + if (state == PM_SUSPEND_MEM) { + pm_data |= AT91_PM_MODE(AT91_PM_SLOW_CLOCK); + if (at91_pm_data.ulp_mode == ULP1_MODE) + pm_data |= AT91_PM_ULP(AT91_PM_ULP1_MODE); + } flush_cache_all(); outer_disable(); @@ -498,3 +505,10 @@ void __init sama5_pm_init(void) at91_pm_data.memctrl = AT91_MEMCTRL_DDRSDR; at91_pm_init(NULL); } + +void __init sama5d2_pm_init(void) +{ + sama5_pm_init(); + + at91_pm_data.ulp_mode = ULP1_MODE; +} diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h index 3fcf881..2e76745 100644 --- a/arch/arm/mach-at91/pm.h +++ b/arch/arm/mach-at91/pm.h @@ -39,4 +39,11 @@ extern void __iomem *at91_ramc_base[]; #define AT91_PM_SLOW_CLOCK 0x01 +#define AT91_PM_ULP_OFFSET 5 +#define AT91_PM_ULP_MASK 0x03 +#define AT91_PM_ULP(x) (((x) & AT91_PM_ULP_MASK) << AT91_PM_ULP_OFFSET) + +#define AT91_PM_ULP0_MODE 0x00 +#define AT91_PM_ULP1_MODE 0x01 + #endif diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index 5fcffdc..de45575 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -41,6 +41,15 @@ tmp2 .req r5 .endm /* + * Wait for main oscillator selection is done + */ + .macro wait_moscsels +1: ldr tmp1, [pmc, #AT91_PMC_SR] + tst tmp1, #AT91_PMC_MOSCSELS + beq 1b + .endm + +/* * Wait until PLLA has locked. */ .macro wait_pllalock @@ -101,6 +110,10 @@ ENTRY(at91_pm_suspend_in_sram) and r0, r0, #AT91_PM_MODE_MASK str r0, .pm_mode + lsr r0, r3, #AT91_PM_ULP_OFFSET + and r0, r0, #AT91_PM_ULP_MASK + str r0, .ulp_mode + /* Active the self-refresh mode */ mov r0, #SRAMC_SELF_FRESH_ACTIVE bl at91_sramc_self_refresh @@ -131,6 +144,13 @@ ENTRY(at91_pm_suspend_in_sram) orr tmp1, tmp1, #(1 << 29) /* bit 29 always set */ str tmp1, [pmc, #AT91_CKGR_PLLAR] + ldr r0, .ulp_mode + tst r0, #AT91_PM_ULP1_MODE + beq ulp0_mode + + bl at91_pm_ulp1_mode + b ulp_exit + ulp0_mode: bl at91_pm_ulp0_mode b ulp_exit @@ -326,6 +346,83 @@ ENTRY(at91_pm_ulp0_mode) mov pc, lr ENDPROC(at91_pm_ulp0_mode) +/** + * void at91_pm_ulp1_mode(void) + * Note: This procedure only applies on the platform which uses + * the external crystal oscillator as a main clock source. + */ +ENTRY(at91_pm_ulp1_mode) + ldr pmc, .pmc_base + + /* Switch the main clock source to 12-MHz RC oscillator */ + ldr tmp1, [pmc, #AT91_CKGR_MOR] + bic tmp1, tmp1, #AT91_PMC_MOSCSEL + bic tmp1, tmp1, #AT91_PMC_KEY_MASK + orr tmp1, tmp1, #AT91_PMC_KEY + str tmp1, [pmc, #AT91_CKGR_MOR] + + wait_moscsels + + /* Disable the crystal oscillator */ + ldr tmp1, [pmc, #AT91_CKGR_MOR] + bic tmp1, tmp1, #AT91_PMC_MOSCEN + bic tmp1, tmp1, #AT91_PMC_KEY_MASK + orr tmp1, tmp1, #AT91_PMC_KEY + str tmp1, [pmc, #AT91_CKGR_MOR] + + /* Switch the master clock source to main clock */ + ldr tmp1, [pmc, #AT91_PMC_MCKR] + bic tmp1, tmp1, #AT91_PMC_CSS + orr tmp1, tmp1, #AT91_PMC_CSS_MAIN + str tmp1, [pmc, #AT91_PMC_MCKR] + + wait_mckrdy + + /* Enter the ULP1 mode by set WAITMODE bit in CKGR_MOR */ + ldr tmp1, [pmc, #AT91_CKGR_MOR] + orr tmp1, tmp1, #AT91_PMC_WAITMODE + bic tmp1, tmp1, #AT91_PMC_KEY_MASK + orr tmp1, tmp1, #AT91_PMC_KEY + str tmp1, [pmc, #AT91_CKGR_MOR] + + wait_mckrdy + + /* Enable the crystal oscillator */ + ldr tmp1, [pmc, #AT91_CKGR_MOR] + orr tmp1, tmp1, #AT91_PMC_MOSCEN + bic tmp1, tmp1, #AT91_PMC_KEY_MASK + orr tmp1, tmp1, #AT91_PMC_KEY + str tmp1, [pmc, #AT91_CKGR_MOR] + + wait_moscrdy + + /* Switch the master clock source to slow clock */ + ldr tmp1, [pmc, #AT91_PMC_MCKR] + bic tmp1, tmp1, #AT91_PMC_CSS + str tmp1, [pmc, #AT91_PMC_MCKR] + + wait_mckrdy + + /* Switch main clock source to crystal oscillator */ + ldr tmp1, [pmc, #AT91_CKGR_MOR] + orr tmp1, tmp1, #AT91_PMC_MOSCSEL + bic tmp1, tmp1, #AT91_PMC_KEY_MASK + orr tmp1, tmp1, #AT91_PMC_KEY + str tmp1, [pmc, #AT91_CKGR_MOR] + + wait_moscsels + + /* Switch the master clock source to main clock */ + ldr tmp1, [pmc, #AT91_PMC_MCKR] + bic tmp1, tmp1, #AT91_PMC_CSS + orr tmp1, tmp1, #AT91_PMC_CSS_MAIN + str tmp1, [pmc, #AT91_PMC_MCKR] + + wait_mckrdy + + mov pc, lr +ENDPROC(at91_pm_ulp1_mode) + .pmc_base: .word 0 .sramc_base: @@ -336,6 +433,8 @@ ENDPROC(at91_pm_ulp0_mode) .word 0 .pm_mode: .word 0 +.ulp_mode: + .word 0 .saved_mckr: .word 0 .saved_pllar: diff --git a/arch/arm/mach-at91/sama5.c b/arch/arm/mach-at91/sama5.c index 2debfe2..5bc3fc8 100644 --- a/arch/arm/mach-at91/sama5.c +++ b/arch/arm/mach-at91/sama5.c @@ -103,6 +103,7 @@ MACHINE_END static void __init sama5d2_dt_device_init(void) { sama5_common_init(); + sama5d2_pm_init(); } static const char *const sama5d2_dt_board_compat[] __initconst = { diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index 17f413b..cec6cc3 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -47,8 +47,10 @@ #define AT91_CKGR_MOR 0x20 /* Main Oscillator Register [not on SAM9RL] */ #define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */ #define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass */ +#define AT91_PMC_WAITMODE (1 << 2) /* Wait Mode Command */ #define AT91_PMC_MOSCRCEN (1 << 3) /* Main On-Chip RC Oscillator Enable [some SAM9] */ #define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */ +#define AT91_PMC_KEY_MASK (0xff << 16) #define AT91_PMC_KEY (0x37 << 16) /* MOR Writing Key */ #define AT91_PMC_MOSCSEL (1 << 24) /* Main Oscillator Selection [some SAM9] */ #define AT91_PMC_CFDEN (1 << 25) /* Clock Failure Detector Enable [some SAM9] */