diff options
-rw-r--r-- | arch/arm/mach-at91/Kconfig | 18 | ||||
-rw-r--r-- | arch/arm/mach-at91/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-at91/pm.c | 139 | ||||
-rw-r--r-- | arch/arm/mach-at91/pm.h | 14 | ||||
-rw-r--r-- | arch/arm/mach-at91/pm_slowclock.S | 335 | ||||
-rw-r--r-- | arch/arm/mach-at91/pm_suspend.S | 338 | ||||
-rw-r--r-- | arch/arm/mach-at91/sama5.c | 20 |
7 files changed, 418 insertions, 448 deletions
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index c74a44324e5b..89276fb0052a 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -24,7 +24,7 @@ config SOC_SAMA5 select GENERIC_CLOCKEVENTS select MEMORY select ATMEL_SDRAMC - select PHYLIB if NETDEVICES + select SRAM if PM menu "Atmel AT91 System-on-Chip" @@ -81,6 +81,7 @@ config SOC_AT91RM9200 select CPU_ARM920T select GENERIC_CLOCKEVENTS select HAVE_AT91_USB_CLK + select SRAM if PM config SOC_AT91SAM9 bool "AT91SAM9" @@ -94,6 +95,7 @@ config SOC_AT91SAM9 select HAVE_AT91_UTMI select HAVE_FB_ATMEL select MEMORY + select SRAM if PM help Select this if you are using one of those Atmel SoC: AT91SAM9260 @@ -116,20 +118,6 @@ endif # SOC_SAM_V4_V5 comment "AT91 Feature Selections" -config AT91_SLOW_CLOCK - bool "Suspend-to-RAM disables main oscillator" - select SRAM - depends on SUSPEND - help - Select this if you want Suspend-to-RAM to save the most power - possible (without powering off the CPU) by disabling the PLLs - and main oscillator so that only the 32 KiHz clock is available. - - When only that slow-clock is available, some peripherals lose - functionality. Many can't issue wakeup events unless faster - clocks are available. Some lose their operating state and - need to be completely re-initialized. - config AT91_TIMER_HZ int "Kernel HZ (jiffies per second)" range 32 1024 diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index 827fdbcce1c7..7df8c854f80f 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_SOC_SAMA5) += sama5.o # Power Management obj-$(CONFIG_PM) += pm.o -obj-$(CONFIG_AT91_SLOW_CLOCK) += pm_slowclock.o +obj-$(CONFIG_PM) += pm_suspend.o ifeq ($(CONFIG_PM_DEBUG),y) CFLAGS_pm.o += -DDEBUG diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index aa4116e9452f..ac947cdd506c 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -29,6 +29,8 @@ #include <linux/atomic.h> #include <asm/mach/time.h> #include <asm/mach/irq.h> +#include <asm/fncpy.h> +#include <asm/cacheflush.h> #include <mach/cpu.h> #include <mach/hardware.h> @@ -41,7 +43,6 @@ static struct { int memctrl; } at91_pm_data; -static void (*at91_pm_standby)(void); void __iomem *at91_ramc_base[2]; static int at91_pm_valid_state(suspend_state_t state) @@ -119,76 +120,67 @@ int at91_suspend_entering_slow_clock(void) } EXPORT_SYMBOL(at91_suspend_entering_slow_clock); - -static void (*slow_clock)(void __iomem *pmc, void __iomem *ramc0, +static void (*at91_suspend_sram_fn)(void __iomem *pmc, void __iomem *ramc0, void __iomem *ramc1, int memctrl); -#ifdef CONFIG_AT91_SLOW_CLOCK -extern void at91_slow_clock(void __iomem *pmc, void __iomem *ramc0, +extern void at91_pm_suspend_in_sram(void __iomem *pmc, void __iomem *ramc0, void __iomem *ramc1, int memctrl); -extern u32 at91_slow_clock_sz; -#endif +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; + + pm_data |= (state == PM_SUSPEND_MEM) ? + AT91_PM_MODE(AT91_PM_SLOW_CLOCK) : 0; + + flush_cache_all(); + outer_disable(); + + at91_suspend_sram_fn(at91_pmc_base, at91_ramc_base[0], + at91_ramc_base[1], pm_data); + + outer_resume(); +} static int at91_pm_enter(suspend_state_t state) { at91_pinctrl_gpio_suspend(); switch (state) { + /* + * Suspend-to-RAM is like STANDBY plus slow clock mode, so + * drivers must suspend more deeply, the master clock switches + * to the clk32k and turns off the main oscillator + */ + case PM_SUSPEND_MEM: /* - * Suspend-to-RAM is like STANDBY plus slow clock mode, so - * drivers must suspend more deeply: only the master clock - * controller may be using the main oscillator. + * Ensure that clocks are in a valid state. */ - case PM_SUSPEND_MEM: - /* - * Ensure that clocks are in a valid state. - */ - if (!at91_pm_verify_clocks()) - goto error; - - /* - * Enter slow clock mode by switching over to clk32k and - * turning off the main oscillator; reverse on wakeup. - */ - if (slow_clock) { -#ifdef CONFIG_AT91_SLOW_CLOCK - /* copy slow_clock handler to SRAM, and call it */ - memcpy(slow_clock, at91_slow_clock, at91_slow_clock_sz); -#endif - slow_clock(at91_pmc_base, at91_ramc_base[0], - at91_ramc_base[1], - at91_pm_data.memctrl); - break; - } else { - pr_info("AT91: PM - no slow clock mode enabled ...\n"); - /* FALLTHROUGH leaving master clock alone */ - } + if (!at91_pm_verify_clocks()) + goto error; - /* - * STANDBY mode has *all* drivers suspended; ignores irqs not - * marked as 'wakeup' event sources; and reduces DRAM power. - * But otherwise it's identical to PM_SUSPEND_ON: cpu idle, and - * nothing fancy done with main or cpu clocks. - */ - case PM_SUSPEND_STANDBY: - /* - * NOTE: the Wait-for-Interrupt instruction needs to be - * in icache so no SDRAM accesses are needed until the - * wakeup IRQ occurs and self-refresh is terminated. - * For ARM 926 based chips, this requirement is weaker - * as at91sam9 can access a RAM in self-refresh mode. - */ - if (at91_pm_standby) - at91_pm_standby(); - break; + at91_pm_suspend(state); - case PM_SUSPEND_ON: - cpu_do_idle(); - break; + break; - default: - pr_debug("AT91: PM - bogus suspend state %d\n", state); - goto error; + /* + * STANDBY mode has *all* drivers suspended; ignores irqs not + * marked as 'wakeup' event sources; and reduces DRAM power. + * But otherwise it's identical to PM_SUSPEND_ON: cpu idle, and + * nothing fancy done with main or cpu clocks. + */ + case PM_SUSPEND_STANDBY: + at91_pm_suspend(state); + break; + + case PM_SUSPEND_ON: + cpu_do_idle(); + break; + + default: + pr_debug("AT91: PM - bogus suspend state %d\n", state); + goto error; } error: @@ -218,12 +210,10 @@ static struct platform_device at91_cpuidle_device = { .name = "cpuidle-at91", }; -void at91_pm_set_standby(void (*at91_standby)(void)) +static void at91_pm_set_standby(void (*at91_standby)(void)) { - if (at91_standby) { + if (at91_standby) at91_cpuidle_device.dev.platform_data = at91_standby; - at91_pm_standby = at91_standby; - } } static const struct of_device_id ramc_ids[] __initconst = { @@ -263,7 +253,6 @@ static __init void at91_dt_ramc(void) at91_pm_set_standby(standby); } -#ifdef CONFIG_AT91_SLOW_CLOCK static void __init at91_pm_sram_init(void) { struct gen_pool *sram_pool; @@ -291,30 +280,36 @@ static void __init at91_pm_sram_init(void) return; } - sram_base = gen_pool_alloc(sram_pool, at91_slow_clock_sz); + sram_base = gen_pool_alloc(sram_pool, at91_pm_suspend_in_sram_sz); if (!sram_base) { - pr_warn("%s: unable to alloc ocram!\n", __func__); + pr_warn("%s: unable to alloc sram!\n", __func__); return; } sram_pbase = gen_pool_virt_to_phys(sram_pool, sram_base); - slow_clock = __arm_ioremap_exec(sram_pbase, at91_slow_clock_sz, false); -} -#endif + 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); +} static void __init at91_pm_init(void) { -#ifdef CONFIG_AT91_SLOW_CLOCK at91_pm_sram_init(); -#endif - - pr_info("AT91: Power Management%s\n", (slow_clock ? " (with slow clock mode)" : "")); if (at91_cpuidle_device.dev.platform_data) platform_device_register(&at91_cpuidle_device); - suspend_set_ops(&at91_pm_ops); + if (at91_suspend_sram_fn) + suspend_set_ops(&at91_pm_ops); + else + pr_info("AT91: PM not supported, due to no SRAM allocated\n"); } void __init at91rm9200_pm_init(void) diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h index 86c0aa819d25..dcacfa1ad3fa 100644 --- a/arch/arm/mach-at91/pm.h +++ b/arch/arm/mach-at91/pm.h @@ -15,11 +15,13 @@ #include <mach/at91_ramc.h> -#ifdef CONFIG_PM -extern void at91_pm_set_standby(void (*at91_standby)(void)); -#else -static inline void at91_pm_set_standby(void (*at91_standby)(void)) { } -#endif +#define AT91_PM_MEMTYPE_MASK 0x0f + +#define AT91_PM_MODE_OFFSET 4 +#define AT91_PM_MODE_MASK 0x01 +#define AT91_PM_MODE(x) (((x) & AT91_PM_MODE_MASK) << AT91_PM_MODE_OFFSET) + +#define AT91_PM_SLOW_CLOCK 0x01 /* * The AT91RM9200 goes into self-refresh mode with this command, and will @@ -31,6 +33,7 @@ static inline void at91_pm_set_standby(void (*at91_standby)(void)) { } * still in self-refresh is "not recommended", but seems to work. */ +#ifndef __ASSEMBLY__ static inline void at91rm9200_standby(void) { u32 lpr = at91_ramc_read(0, AT91RM9200_SDRAMC_LPR); @@ -112,3 +115,4 @@ static inline void at91sam9_sdram_standby(void) } #endif +#endif diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S deleted file mode 100644 index 931f0e302c03..000000000000 --- a/arch/arm/mach-at91/pm_slowclock.S +++ /dev/null @@ -1,335 +0,0 @@ -/* - * arch/arm/mach-at91/pm_slow_clock.S - * - * Copyright (C) 2006 Savin Zlobec - * - * AT91SAM9 support: - * Copyright (C) 2007 Anti Sullin <[email protected] - * - * 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 <mach/hardware.h> -#include <mach/at91_ramc.h> - -/* - * When SLOWDOWN_MASTER_CLOCK is defined we will also slow down the Master - * clock during suspend by adjusting its prescalar and divisor. - * NOTE: This hasn't been shown to be stable on SAM9s; and on the RM9200 there - * are errata regarding adjusting the prescalar and divisor. - */ -#undef SLOWDOWN_MASTER_CLOCK - -pmc .req r0 -sdramc .req r1 -ramc1 .req r2 -memctrl .req r3 -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 - -/* - * Wait until PLLB has locked. - */ - .macro wait_pllblock -1: ldr tmp1, [pmc, #AT91_PMC_SR] - tst tmp1, #AT91_PMC_LOCKB - beq 1b - .endm - - .text - - .arm - -/* void at91_slow_clock(void __iomem *pmc, void __iomem *sdramc, - * void __iomem *ramc1, int memctrl) - */ -ENTRY(at91_slow_clock) - /* Save registers on stack */ - stmfd sp!, {r4 - r12, lr} - - /* - * Register usage: - * R0 = Base address of AT91_PMC - * R1 = Base address of RAM Controller (SDRAM, DDRSDR, or AT91_SYS) - * R2 = Base address of second RAM Controller or 0 if not present - * R3 = Memory controller - * R4 = temporary register - * R5 = temporary register - */ - - /* Drain write buffer */ - mov tmp1, #0 - mcr p15, 0, tmp1, c7, c10, 4 - - cmp memctrl, #AT91_MEMCTRL_MC - bne ddr_sr_enable - - /* - * at91rm9200 Memory controller - */ - /* Put SDRAM in self-refresh mode */ - mov tmp1, #1 - str tmp1, [sdramc, #AT91RM9200_SDRAMC_SRR] - b sdr_sr_done - - /* - * DDRSDR Memory controller - */ -ddr_sr_enable: - cmp memctrl, #AT91_MEMCTRL_DDRSDR - bne sdr_sr_enable - - /* LPDDR1 --> force DDR2 mode during self-refresh */ - ldr tmp1, [sdramc, #AT91_DDRSDRC_MDR] - str tmp1, .saved_sam9_mdr - bic tmp1, tmp1, #~AT91_DDRSDRC_MD - cmp tmp1, #AT91_DDRSDRC_MD_LOW_POWER_DDR - ldreq tmp1, [sdramc, #AT91_DDRSDRC_MDR] - biceq tmp1, tmp1, #AT91_DDRSDRC_MD - orreq tmp1, tmp1, #AT91_DDRSDRC_MD_DDR2 - streq tmp1, [sdramc, #AT91_DDRSDRC_MDR] - - /* prepare for DDRAM self-refresh mode */ - ldr tmp1, [sdramc, #AT91_DDRSDRC_LPR] - str tmp1, .saved_sam9_lpr - bic tmp1, #AT91_DDRSDRC_LPCB - orr tmp1, #AT91_DDRSDRC_LPCB_SELF_REFRESH - - /* figure out if we use the second ram controller */ - cmp ramc1, #0 - beq ddr_no_2nd_ctrl - - ldr tmp2, [ramc1, #AT91_DDRSDRC_MDR] - str tmp2, .saved_sam9_mdr1 - bic tmp2, tmp2, #~AT91_DDRSDRC_MD - cmp tmp2, #AT91_DDRSDRC_MD_LOW_POWER_DDR - ldreq tmp2, [ramc1, #AT91_DDRSDRC_MDR] - biceq tmp2, tmp2, #AT91_DDRSDRC_MD - orreq tmp2, tmp2, #AT91_DDRSDRC_MD_DDR2 - streq tmp2, [ramc1, #AT91_DDRSDRC_MDR] - - ldr tmp2, [ramc1, #AT91_DDRSDRC_LPR] - str tmp2, .saved_sam9_lpr1 - bic tmp2, #AT91_DDRSDRC_LPCB - orr tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH - - /* Enable DDRAM self-refresh mode */ - str tmp2, [ramc1, #AT91_DDRSDRC_LPR] -ddr_no_2nd_ctrl: - str tmp1, [sdramc, #AT91_DDRSDRC_LPR] - - b sdr_sr_done - - /* - * SDRAMC Memory controller - */ -sdr_sr_enable: - /* Enable SDRAM self-refresh mode */ - ldr tmp1, [sdramc, #AT91_SDRAMC_LPR] - str tmp1, .saved_sam9_lpr - - bic tmp1, #AT91_SDRAMC_LPCB - orr tmp1, #AT91_SDRAMC_LPCB_SELF_REFRESH - str tmp1, [sdramc, #AT91_SDRAMC_LPR] - -sdr_sr_done: - /* 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 - -#ifdef SLOWDOWN_MASTER_CLOCK - /* - * Set the Master Clock PRES and MDIV fields. - * - * See AT91RM9200 errata #27 and #28 for details. - */ - mov tmp1, #0 - str tmp1, [pmc, #AT91_PMC_MCKR] - - wait_mckrdy -#endif - - /* 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] - - /* Save PLLB setting and disable it */ - ldr tmp1, [pmc, #AT91_CKGR_PLLBR] - str tmp1, .saved_pllbr - - mov tmp1, #AT91_PMC_PLLCOUNT - str tmp1, [pmc, #AT91_CKGR_PLLBR] - - /* 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] - - /* Wait for interrupt */ - mcr p15, 0, tmp1, c7, c0, 4 - - /* 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 PLLB setting */ - ldr tmp1, .saved_pllbr - str tmp1, [pmc, #AT91_CKGR_PLLBR] - - tst tmp1, #(AT91_PMC_MUL & 0xff0000) - bne 1f - tst tmp1, #(AT91_PMC_MUL & ~0xff0000) - beq 2f -1: - wait_pllblock -2: - - /* 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: - -#ifdef SLOWDOWN_MASTER_CLOCK - /* - * First set PRES if it was not 0, - * than set CSS and MDIV fields. - * - * See AT91RM9200 errata #27 and #28 for details. - */ - ldr tmp1, .saved_mckr - tst tmp1, #AT91_PMC_PRES - beq 2f - and tmp1, tmp1, #AT91_PMC_PRES - str tmp1, [pmc, #AT91_PMC_MCKR] - - wait_mckrdy -#endif - - /* - * Restore master clock setting - */ -2: ldr tmp1, .saved_mckr - str tmp1, [pmc, #AT91_PMC_MCKR] - - wait_mckrdy - - /* - * at91rm9200 Memory controller - * Do nothing - self-refresh is automatically disabled. - */ - cmp memctrl, #AT91_MEMCTRL_MC - beq ram_restored - - /* - * DDRSDR Memory controller - */ - cmp memctrl, #AT91_MEMCTRL_DDRSDR - bne sdr_en_restore - /* Restore MDR in case of LPDDR1 */ - ldr tmp1, .saved_sam9_mdr - str tmp1, [sdramc, #AT91_DDRSDRC_MDR] - /* Restore LPR on AT91 with DDRAM */ - ldr tmp1, .saved_sam9_lpr - str tmp1, [sdramc, #AT91_DDRSDRC_LPR] - - /* if we use the second ram controller */ - cmp ramc1, #0 - ldrne tmp2, .saved_sam9_mdr1 - strne tmp2, [ramc1, #AT91_DDRSDRC_MDR] - ldrne tmp2, .saved_sam9_lpr1 - strne tmp2, [ramc1, #AT91_DDRSDRC_LPR] - - b ram_restored - - /* - * SDRAMC Memory controller - */ -sdr_en_restore: - /* Restore LPR on AT91 with SDRAM */ - ldr tmp1, .saved_sam9_lpr - str tmp1, [sdramc, #AT91_SDRAMC_LPR] - -ram_restored: - /* Restore registers, and return */ - ldmfd sp!, {r4 - r12, pc} - - -.saved_mckr: - .word 0 - -.saved_pllar: - .word 0 - -.saved_pllbr: - .word 0 - -.saved_sam9_lpr: - .word 0 - -.saved_sam9_lpr1: - .word 0 - -.saved_sam9_mdr: - .word 0 - -.saved_sam9_mdr1: - .word 0 - -ENTRY(at91_slow_clock_sz) - .word .-at91_slow_clock diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S new file mode 100644 index 000000000000..7c444c259740 --- /dev/null +++ b/arch/arm/mach-at91/pm_suspend.S @@ -0,0 +1,338 @@ +/* + * arch/arm/mach-at91/pm_slow_clock.S + * + * Copyright (C) 2006 Savin Zlobec + * + * AT91SAM9 support: + * Copyright (C) 2007 Anti Sullin <[email protected] + * + * 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 <mach/hardware.h> +#include <mach/at91_ramc.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 + */ +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, #AT91RM9200_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 diff --git a/arch/arm/mach-at91/sama5.c b/arch/arm/mach-at91/sama5.c index 03dcb441f3d2..23d067a91cff 100644 --- a/arch/arm/mach-at91/sama5.c +++ b/arch/arm/mach-at91/sama5.c @@ -11,13 +11,10 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/gpio.h> -#include <linux/micrel_phy.h> #include <linux/of.h> #include <linux/of_irq.h> #include <linux/of_platform.h> -#include <linux/phy.h> #include <linux/clk-provider.h> -#include <linux/phy.h> #include <mach/hardware.h> @@ -29,25 +26,8 @@ #include "generic.h" -static int ksz8081_phy_fixup(struct phy_device *phy) -{ - int value; - - value = phy_read(phy, 0x16); - value &= ~0x20; - phy_write(phy, 0x16, value); - - return 0; -} - static void __init sama5_dt_device_init(void) { - if (of_machine_is_compatible("atmel,sama5d4ek") && - IS_ENABLED(CONFIG_PHYLIB)) { - phy_register_fixup_for_id("fc028000.etherne:00", - ksz8081_phy_fixup); - } - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); at91sam9x5_pm_init(); } |