Using the PIE infrastructure allows to write the whole suspend/resume
functions in C instead of assembly.

The only remaining assembly instruction is wfi for armv5
It makes the code shorter and clearer.

Signed-off-by: Alexandre Belloni <alexandre.bell...@free-electrons.com>
---
 arch/arm/mach-at91/Kconfig       |   1 +
 arch/arm/mach-at91/Makefile      |   2 +-
 arch/arm/mach-at91/pm.c          |  31 ++--
 arch/arm/mach-at91/pm/.gitignore |   2 +
 arch/arm/mach-at91/pm/Makefile   |   3 +
 arch/arm/mach-at91/pm/atmel_pm.c |  97 +++++++++++
 arch/arm/mach-at91/pm_suspend.S  | 338 ---------------------------------------
 7 files changed, 114 insertions(+), 360 deletions(-)
 create mode 100644 arch/arm/mach-at91/pm/.gitignore
 create mode 100644 arch/arm/mach-at91/pm/Makefile
 create mode 100644 arch/arm/mach-at91/pm/atmel_pm.c
 delete mode 100644 arch/arm/mach-at91/pm_suspend.S

diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 08047afdf38e..ab430c04a699 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -5,6 +5,7 @@ menuconfig ARCH_AT91
        select COMMON_CLK_AT91
        select PINCTRL
        select SOC_BUS
+       select PIE
 
 if ARCH_AT91
 config SOC_SAMA5D2
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index c5bbf8bb8c0f..062336de4f66 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_SOC_SAMA5)               += sama5.o
 
 # Power Management
 obj-$(CONFIG_PM)               += pm.o
-obj-$(CONFIG_PM)               += pm_suspend.o
+obj-$(CONFIG_PM)               += pm/
 
 ifeq ($(CONFIG_CPU_V7),y)
 AFLAGS_pm_suspend.o := -march=armv7-a
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index f06270198bf1..f2f2a97ee1de 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -21,6 +21,7 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/of_address.h>
+#include <linux/pie.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/clk/at91_pmc.h>
@@ -56,6 +57,8 @@ static struct {
 
 void __iomem *at91_ramc_base[2];
 
+static struct pie_chunk *atmel_pm_pie;
+
 static int at91_pm_valid_state(suspend_state_t state)
 {
        switch (state) {
@@ -133,10 +136,6 @@ EXPORT_SYMBOL(at91_suspend_entering_slow_clock);
 static void (*at91_suspend_sram_fn)(void __iomem *pmc, void __iomem *ramc0,
                          void __iomem *ramc1, int memctrl);
 
-extern void at91_pm_suspend_in_sram(void __iomem *pmc, void __iomem *ramc0,
-                           void __iomem *ramc1, int memctrl);
-extern u32 at91_pm_suspend_in_sram_sz;
-
 static void at91_pm_suspend(suspend_state_t state)
 {
        unsigned int pm_data = at91_pm_data.memctrl;
@@ -370,11 +369,12 @@ void at91sam9_idle(void)
        cpu_do_idle();
 }
 
+extern void atmel_pm_suspend(void __iomem *pmc, void __iomem *ramc0,
+                            void __iomem *ramc1, int memctrl);
+
 static void __init at91_pm_sram_init(void)
 {
        struct gen_pool *sram_pool;
-       phys_addr_t sram_pbase;
-       unsigned long sram_base;
        struct device_node *node;
        struct platform_device *pdev = NULL;
 
@@ -397,23 +397,12 @@ static void __init at91_pm_sram_init(void)
                return;
        }
 
-       sram_base = gen_pool_alloc(sram_pool, at91_pm_suspend_in_sram_sz);
-       if (!sram_base) {
-               pr_warn("%s: unable to alloc sram!\n", __func__);
+       atmel_pm_pie = pie_load_sections(sram_pool, atmel_pm,
+                                        arch_arm_mach_at91_pm);
+       if (IS_ERR(atmel_pm_pie))
                return;
-       }
-
-       sram_pbase = gen_pool_virt_to_phys(sram_pool, sram_base);
-       at91_suspend_sram_fn = __arm_ioremap_exec(sram_pbase,
-                                       at91_pm_suspend_in_sram_sz, false);
-       if (!at91_suspend_sram_fn) {
-               pr_warn("SRAM: Could not map\n");
-               return;
-       }
 
-       /* Copy the pm suspend handler to SRAM */
-       at91_suspend_sram_fn = fncpy(at91_suspend_sram_fn,
-                       &at91_pm_suspend_in_sram, at91_pm_suspend_in_sram_sz);
+       at91_suspend_sram_fn = fn_to_pie(atmel_pm_pie, atmel_pm_suspend);
 }
 
 static const struct of_device_id atmel_pmc_ids[] __initconst = {
diff --git a/arch/arm/mach-at91/pm/.gitignore b/arch/arm/mach-at91/pm/.gitignore
new file mode 100644
index 000000000000..1cb8879eb0bf
--- /dev/null
+++ b/arch/arm/mach-at91/pm/.gitignore
@@ -0,0 +1,2 @@
+*.lds*
+*.syms
diff --git a/arch/arm/mach-at91/pm/Makefile b/arch/arm/mach-at91/pm/Makefile
new file mode 100644
index 000000000000..c12d54862c10
--- /dev/null
+++ b/arch/arm/mach-at91/pm/Makefile
@@ -0,0 +1,3 @@
+PIE_NAME := atmel_pm
+
+include arch/arm/pie/Makefile.pie
diff --git a/arch/arm/mach-at91/pm/atmel_pm.c b/arch/arm/mach-at91/pm/atmel_pm.c
new file mode 100644
index 000000000000..7f391addd2da
--- /dev/null
+++ b/arch/arm/mach-at91/pm/atmel_pm.c
@@ -0,0 +1,97 @@
+#include <linux/io.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/mfd/syscon/atmel-mc.h>
+#include <linux/pie.h>
+#include "../pm.h"
+
+#define        SRAMC_SELF_FRESH_ACTIVE         0x01
+#define        SRAMC_SELF_FRESH_EXIT           0x00
+
+static void at91_sramc_self_refresh(unsigned int is_active,
+                                   unsigned int memtype,
+                                   void __iomem *sdramc_base,
+                                   void __iomem *sdramc_base1)
+{
+       static unsigned int lpr, mdr, lpr1, mdr1;
+
+       switch (memtype) {
+       case AT91_MEMCTRL_MC:
+       /*
+        * at91rm9200 Memory controller
+        */
+               if (is_active)
+                       __raw_writel(1, sdramc_base + AT91_MC_SDRAMC_SRR);
+               break;
+
+       case AT91_MEMCTRL_DDRSDR:
+               if (is_active) {
+                       mdr = __raw_readl(sdramc_base + AT91_DDRSDRC_MDR);
+                       lpr = __raw_readl(sdramc_base + AT91_DDRSDRC_LPR);
+
+                       if ((mdr & AT91_DDRSDRC_MD) == 
AT91_DDRSDRC_MD_LOW_POWER_DDR)
+                               __raw_writel((mdr & ~AT91_DDRSDRC_MD) |
+                                            AT91_DDRSDRC_MD_DDR2, sdramc_base +
+                                            AT91_DDRSDRC_MDR);
+                       __raw_writel((lpr & ~AT91_DDRSDRC_LPCB) |
+                                    AT91_DDRSDRC_LPCB_SELF_REFRESH, sdramc_base
+                                    + AT91_DDRSDRC_LPR);
+
+                       if (sdramc_base1) {
+                               mdr1 = __raw_readl(sdramc_base1 + 
AT91_DDRSDRC_MDR);
+                               lpr1 = __raw_readl(sdramc_base1 + 
AT91_DDRSDRC_LPR);
+                               if ((mdr1 & AT91_DDRSDRC_MD) == 
AT91_DDRSDRC_MD_LOW_POWER_DDR)
+                                       __raw_writel((mdr1 & ~AT91_DDRSDRC_MD) |
+                                                    AT91_DDRSDRC_MD_DDR2,
+                                                    sdramc_base1 +
+                                                    AT91_DDRSDRC_MDR);
+                               __raw_writel((lpr1 & ~AT91_DDRSDRC_LPCB) |
+                                            AT91_DDRSDRC_LPCB_SELF_REFRESH,
+                                            sdramc_base1 + AT91_DDRSDRC_LPR);
+                       }
+               } else {
+                       __raw_writel(mdr, sdramc_base + AT91_DDRSDRC_MDR);
+                       __raw_writel(lpr, sdramc_base + AT91_DDRSDRC_LPR);
+                       if (sdramc_base1) {
+                               __raw_writel(mdr, sdramc_base1 + 
AT91_DDRSDRC_MDR);
+                               __raw_writel(lpr, sdramc_base1 + 
AT91_DDRSDRC_LPR);
+                       }
+               }
+               break;
+
+       case AT91_MEMCTRL_SDRAMC:
+               if (is_active) {
+                       lpr = __raw_readl(sdramc_base + AT91_SDRAMC_LPR);
+
+                       __raw_writel((lpr & ~AT91_SDRAMC_LPCB) |
+                                    AT91_SDRAMC_LPCB_SELF_REFRESH, sdramc_base
+                                    + AT91_SDRAMC_LPR);
+               } else {
+                       __raw_writel(lpr, sdramc_base + AT91_SDRAMC_LPR);
+               }
+               break;
+       }
+}
+
+void atmel_pm_suspend(void __iomem *pmc, void __iomem *ramc0,
+                     void __iomem *ramc1, int memctrl)
+{
+       int memtype, pm_mode;
+
+       memtype = memctrl & AT91_PM_MEMTYPE_MASK;
+       pm_mode = (memctrl >> AT91_PM_MODE_OFFSET) & AT91_PM_MODE_MASK;
+
+       dsb();
+
+       at91_sramc_self_refresh(1, memtype, ramc0, ramc1);
+
+#if defined(CONFIG_CPU_V7)
+       dsb();
+       wfi();
+#else
+       asm volatile ("mcr      p15, 0, %0, c7, c0, 4" \
+                     : : "r" (0) : "memory");
+#endif
+
+       at91_sramc_self_refresh(0, memtype, ramc0, ramc1);
+}
+EXPORT_PIE_SYMBOL(atmel_pm_suspend);
diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S
deleted file mode 100644
index a25defda3d22..000000000000
--- a/arch/arm/mach-at91/pm_suspend.S
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * arch/arm/mach-at91/pm_slow_clock.S
- *
- *  Copyright (C) 2006 Savin Zlobec
- *
- * AT91SAM9 support:
- *  Copyright (C) 2007 Anti Sullin <anti.sul...@artecdesign.ee
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-#include <linux/linkage.h>
-#include <linux/clk/at91_pmc.h>
-#include "pm.h"
-
-#define        SRAMC_SELF_FRESH_ACTIVE         0x01
-#define        SRAMC_SELF_FRESH_EXIT           0x00
-
-pmc    .req    r0
-tmp1   .req    r4
-tmp2   .req    r5
-
-/*
- * Wait until master clock is ready (after switching master clock source)
- */
-       .macro wait_mckrdy
-1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
-       tst     tmp1, #AT91_PMC_MCKRDY
-       beq     1b
-       .endm
-
-/*
- * Wait until master oscillator has stabilized.
- */
-       .macro wait_moscrdy
-1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
-       tst     tmp1, #AT91_PMC_MOSCS
-       beq     1b
-       .endm
-
-/*
- * Wait until PLLA has locked.
- */
-       .macro wait_pllalock
-1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
-       tst     tmp1, #AT91_PMC_LOCKA
-       beq     1b
-       .endm
-
-/*
- * Put the processor to enter the idle state
- */
-       .macro at91_cpu_idle
-
-#if defined(CONFIG_CPU_V7)
-       mov     tmp1, #AT91_PMC_PCK
-       str     tmp1, [pmc, #AT91_PMC_SCDR]
-
-       dsb
-
-       wfi             @ Wait For Interrupt
-#else
-       mcr     p15, 0, tmp1, c7, c0, 4
-#endif
-
-       .endm
-
-       .text
-
-       .arm
-
-/*
- * void at91_pm_suspend_in_sram(void __iomem *pmc, void __iomem *sdramc,
- *                     void __iomem *ramc1, int memctrl)
- * @input param:
- *     @r0: base address of AT91_PMC
- *     @r1: base address of SDRAM Controller (SDRAM, DDRSDR, or AT91_SYS)
- *     @r2: base address of second SDRAM Controller or 0 if not present
- *     @r3: pm information
- */
-/* at91_pm_suspend_in_sram must be 8-byte aligned per the requirements of 
fncpy() */
-       .align 3
-ENTRY(at91_pm_suspend_in_sram)
-       /* Save registers on stack */
-       stmfd   sp!, {r4 - r12, lr}
-
-       /* Drain write buffer */
-       mov     tmp1, #0
-       mcr     p15, 0, tmp1, c7, c10, 4
-
-       str     r0, .pmc_base
-       str     r1, .sramc_base
-       str     r2, .sramc1_base
-
-       and     r0, r3, #AT91_PM_MEMTYPE_MASK
-       str     r0, .memtype
-
-       lsr     r0, r3, #AT91_PM_MODE_OFFSET
-       and     r0, r0, #AT91_PM_MODE_MASK
-       str     r0, .pm_mode
-
-       /* Active the self-refresh mode */
-       mov     r0, #SRAMC_SELF_FRESH_ACTIVE
-       bl      at91_sramc_self_refresh
-
-       ldr     r0, .pm_mode
-       tst     r0, #AT91_PM_SLOW_CLOCK
-       beq     skip_disable_main_clock
-
-       ldr     pmc, .pmc_base
-
-       /* Save Master clock setting */
-       ldr     tmp1, [pmc, #AT91_PMC_MCKR]
-       str     tmp1, .saved_mckr
-
-       /*
-        * Set the Master clock source to slow clock
-        */
-       bic     tmp1, tmp1, #AT91_PMC_CSS
-       str     tmp1, [pmc, #AT91_PMC_MCKR]
-
-       wait_mckrdy
-
-       /* Save PLLA setting and disable it */
-       ldr     tmp1, [pmc, #AT91_CKGR_PLLAR]
-       str     tmp1, .saved_pllar
-
-       mov     tmp1, #AT91_PMC_PLLCOUNT
-       orr     tmp1, tmp1, #(1 << 29)          /* bit 29 always set */
-       str     tmp1, [pmc, #AT91_CKGR_PLLAR]
-
-       /* Turn off the main oscillator */
-       ldr     tmp1, [pmc, #AT91_CKGR_MOR]
-       bic     tmp1, tmp1, #AT91_PMC_MOSCEN
-       orr     tmp1, tmp1, #AT91_PMC_KEY
-       str     tmp1, [pmc, #AT91_CKGR_MOR]
-
-skip_disable_main_clock:
-       ldr     pmc, .pmc_base
-
-       /* Wait for interrupt */
-       at91_cpu_idle
-
-       ldr     r0, .pm_mode
-       tst     r0, #AT91_PM_SLOW_CLOCK
-       beq     skip_enable_main_clock
-
-       ldr     pmc, .pmc_base
-
-       /* Turn on the main oscillator */
-       ldr     tmp1, [pmc, #AT91_CKGR_MOR]
-       orr     tmp1, tmp1, #AT91_PMC_MOSCEN
-       orr     tmp1, tmp1, #AT91_PMC_KEY
-       str     tmp1, [pmc, #AT91_CKGR_MOR]
-
-       wait_moscrdy
-
-       /* Restore PLLA setting */
-       ldr     tmp1, .saved_pllar
-       str     tmp1, [pmc, #AT91_CKGR_PLLAR]
-
-       tst     tmp1, #(AT91_PMC_MUL &  0xff0000)
-       bne     3f
-       tst     tmp1, #(AT91_PMC_MUL & ~0xff0000)
-       beq     4f
-3:
-       wait_pllalock
-4:
-
-       /*
-        * Restore master clock setting
-        */
-       ldr     tmp1, .saved_mckr
-       str     tmp1, [pmc, #AT91_PMC_MCKR]
-
-       wait_mckrdy
-
-skip_enable_main_clock:
-       /* Exit the self-refresh mode */
-       mov     r0, #SRAMC_SELF_FRESH_EXIT
-       bl      at91_sramc_self_refresh
-
-       /* Restore registers, and return */
-       ldmfd   sp!, {r4 - r12, pc}
-ENDPROC(at91_pm_suspend_in_sram)
-
-/*
- * void at91_sramc_self_refresh(unsigned int is_active)
- *
- * @input param:
- *     @r0: 1 - active self-refresh mode
- *          0 - exit self-refresh mode
- * register usage:
- *     @r1: memory type
- *     @r2: base address of the sram controller
- */
-
-ENTRY(at91_sramc_self_refresh)
-       ldr     r1, .memtype
-       ldr     r2, .sramc_base
-
-       cmp     r1, #AT91_MEMCTRL_MC
-       bne     ddrc_sf
-
-       /*
-        * at91rm9200 Memory controller
-        */
-
-        /*
-         * For exiting the self-refresh mode, do nothing,
-         * automatically exit the self-refresh mode.
-         */
-       tst     r0, #SRAMC_SELF_FRESH_ACTIVE
-       beq     exit_sramc_sf
-
-       /* Active SDRAM self-refresh mode */
-       mov     r3, #1
-       str     r3, [r2, #AT91_MC_SDRAMC_SRR]
-       b       exit_sramc_sf
-
-ddrc_sf:
-       cmp     r1, #AT91_MEMCTRL_DDRSDR
-       bne     sdramc_sf
-
-       /*
-        * DDR Memory controller
-        */
-       tst     r0, #SRAMC_SELF_FRESH_ACTIVE
-       beq     ddrc_exit_sf
-
-       /* LPDDR1 --> force DDR2 mode during self-refresh */
-       ldr     r3, [r2, #AT91_DDRSDRC_MDR]
-       str     r3, .saved_sam9_mdr
-       bic     r3, r3, #~AT91_DDRSDRC_MD
-       cmp     r3, #AT91_DDRSDRC_MD_LOW_POWER_DDR
-       ldreq   r3, [r2, #AT91_DDRSDRC_MDR]
-       biceq   r3, r3, #AT91_DDRSDRC_MD
-       orreq   r3, r3, #AT91_DDRSDRC_MD_DDR2
-       streq   r3, [r2, #AT91_DDRSDRC_MDR]
-
-       /* Active DDRC self-refresh mode */
-       ldr     r3, [r2, #AT91_DDRSDRC_LPR]
-       str     r3, .saved_sam9_lpr
-       bic     r3, r3, #AT91_DDRSDRC_LPCB
-       orr     r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
-       str     r3, [r2, #AT91_DDRSDRC_LPR]
-
-       /* If using the 2nd ddr controller */
-       ldr     r2, .sramc1_base
-       cmp     r2, #0
-       beq     no_2nd_ddrc
-
-       ldr     r3, [r2, #AT91_DDRSDRC_MDR]
-       str     r3, .saved_sam9_mdr1
-       bic     r3, r3, #~AT91_DDRSDRC_MD
-       cmp     r3, #AT91_DDRSDRC_MD_LOW_POWER_DDR
-       ldreq   r3, [r2, #AT91_DDRSDRC_MDR]
-       biceq   r3, r3, #AT91_DDRSDRC_MD
-       orreq   r3, r3, #AT91_DDRSDRC_MD_DDR2
-       streq   r3, [r2, #AT91_DDRSDRC_MDR]
-
-       /* Active DDRC self-refresh mode */
-       ldr     r3, [r2, #AT91_DDRSDRC_LPR]
-       str     r3, .saved_sam9_lpr1
-       bic     r3, r3, #AT91_DDRSDRC_LPCB
-       orr     r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
-       str     r3, [r2, #AT91_DDRSDRC_LPR]
-
-no_2nd_ddrc:
-       b       exit_sramc_sf
-
-ddrc_exit_sf:
-       /* Restore MDR in case of LPDDR1 */
-       ldr     r3, .saved_sam9_mdr
-       str     r3, [r2, #AT91_DDRSDRC_MDR]
-       /* Restore LPR on AT91 with DDRAM */
-       ldr     r3, .saved_sam9_lpr
-       str     r3, [r2, #AT91_DDRSDRC_LPR]
-
-       /* If using the 2nd ddr controller */
-       ldr     r2, .sramc1_base
-       cmp     r2, #0
-       ldrne   r3, .saved_sam9_mdr1
-       strne   r3, [r2, #AT91_DDRSDRC_MDR]
-       ldrne   r3, .saved_sam9_lpr1
-       strne   r3, [r2, #AT91_DDRSDRC_LPR]
-
-       b       exit_sramc_sf
-
-       /*
-        * SDRAMC Memory controller
-        */
-sdramc_sf:
-       tst     r0, #SRAMC_SELF_FRESH_ACTIVE
-       beq     sdramc_exit_sf
-
-       /* Active SDRAMC self-refresh mode */
-       ldr     r3, [r2, #AT91_SDRAMC_LPR]
-       str     r3, .saved_sam9_lpr
-       bic     r3, r3, #AT91_SDRAMC_LPCB
-       orr     r3, r3, #AT91_SDRAMC_LPCB_SELF_REFRESH
-       str     r3, [r2, #AT91_SDRAMC_LPR]
-
-sdramc_exit_sf:
-       ldr     r3, .saved_sam9_lpr
-       str     r3, [r2, #AT91_SDRAMC_LPR]
-
-exit_sramc_sf:
-       mov     pc, lr
-ENDPROC(at91_sramc_self_refresh)
-
-.pmc_base:
-       .word 0
-.sramc_base:
-       .word 0
-.sramc1_base:
-       .word 0
-.memtype:
-       .word 0
-.pm_mode:
-       .word 0
-.saved_mckr:
-       .word 0
-.saved_pllar:
-       .word 0
-.saved_sam9_lpr:
-       .word 0
-.saved_sam9_lpr1:
-       .word 0
-.saved_sam9_mdr:
-       .word 0
-.saved_sam9_mdr1:
-       .word 0
-
-ENTRY(at91_pm_suspend_in_sram_sz)
-       .word .-at91_pm_suspend_in_sram
-- 
2.8.1

Reply via email to