123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- /*
- * arch/arm/mach-at91/pm_slow_clock.S
- *
- * Copyright (C) 2006 Savin Zlobec
- *
- * AT91SAM9 support:
- * Copyright (C) 2007 Anti Sullin <anti.sullin@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"
- #include "generated/at91_pm_data-offsets.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 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
- 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_suspend_sram_fn(struct at91_pm_data*)
- * @input param:
- * @r0: base address of struct at91_pm_data
- */
- /* 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
- ldr tmp1, [r0, #PM_DATA_PMC]
- str tmp1, .pmc_base
- ldr tmp1, [r0, #PM_DATA_RAMC0]
- str tmp1, .sramc_base
- ldr tmp1, [r0, #PM_DATA_RAMC1]
- str tmp1, .sramc1_base
- ldr tmp1, [r0, #PM_DATA_MEMCTRL]
- str tmp1, .memtype
- ldr tmp1, [r0, #PM_DATA_MODE]
- str tmp1, .pm_mode
- /* Both ldrne below are here to preload their address in the TLB */
- ldr tmp1, [r0, #PM_DATA_SHDWC]
- str tmp1, .shdwc
- cmp tmp1, #0
- ldrne tmp2, [tmp1, #0]
- ldr tmp1, [r0, #PM_DATA_SFRBU]
- str tmp1, .sfr
- cmp tmp1, #0
- ldrne tmp2, [tmp1, #0x10]
- /* Active the self-refresh mode */
- mov r0, #SRAMC_SELF_FRESH_ACTIVE
- bl at91_sramc_self_refresh
- ldr r0, .pm_mode
- cmp r0, #AT91_PM_STANDBY
- beq standby
- cmp r0, #AT91_PM_BACKUP
- beq backup_mode
- bl at91_ulp_mode
- b exit_suspend
- standby:
- /* Wait for interrupt */
- ldr pmc, .pmc_base
- at91_cpu_idle
- b exit_suspend
- backup_mode:
- bl at91_backup_mode
- b exit_suspend
- exit_suspend:
- /* 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)
- ENTRY(at91_backup_mode)
- /*BUMEN*/
- ldr r0, .sfr
- mov tmp1, #0x1
- str tmp1, [r0, #0x10]
- /* Shutdown */
- ldr r0, .shdwc
- mov tmp1, #0xA5000000
- add tmp1, tmp1, #0x1
- str tmp1, [r0, #0]
- ENDPROC(at91_backup_mode)
- .macro at91_pm_ulp0_mode
- ldr pmc, .pmc_base
- /* Turn off the crystal 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 */
- at91_cpu_idle
- /* Turn on the crystal 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
- .endm
- /**
- * Note: This procedure only applies on the platform which uses
- * the external crystal oscillator as a main clock source.
- */
- .macro 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]
- /* Quirk for SAM9X60's PMC */
- nop
- nop
- 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
- .endm
- ENTRY(at91_ulp_mode)
- 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]
- ldr r0, .pm_mode
- cmp r0, #AT91_PM_ULP1
- beq ulp1_mode
- at91_pm_ulp0_mode
- b ulp_exit
- ulp1_mode:
- at91_pm_ulp1_mode
- b ulp_exit
- ulp_exit:
- ldr pmc, .pmc_base
- /* 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
- mov pc, lr
- ENDPROC(at91_ulp_mode)
- /*
- * 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
- .shdwc:
- .word 0
- .sfr:
- .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
|