| 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		0x00pmc	.req	r0tmp1	.req	r4tmp2	.req	r5/* * Wait until master clock is ready (after switching master clock source) */	.macro wait_mckrdy1:	ldr	tmp1, [pmc, #AT91_PMC_SR]	tst	tmp1, #AT91_PMC_MCKRDY	beq	1b	.endm/* * Wait until master oscillator has stabilized. */	.macro wait_moscrdy1:	ldr	tmp1, [pmc, #AT91_PMC_SR]	tst	tmp1, #AT91_PMC_MOSCS	beq	1b	.endm/* * Wait for main oscillator selection is done */	.macro wait_moscsels1:	ldr	tmp1, [pmc, #AT91_PMC_SR]	tst	tmp1, #AT91_PMC_MOSCSELS	beq	1b	.endm/* * Wait until PLLA has locked. */	.macro wait_pllalock1:	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 3ENTRY(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_suspendstandby:	/* Wait for interrupt */	ldr	pmc, .pmc_base	at91_cpu_idle	b	exit_suspendbackup_mode:	bl	at91_backup_mode	b	exit_suspendexit_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.endmENTRY(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_exitulp1_mode:	at91_pm_ulp1_mode	b	ulp_exitulp_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	4f3:	wait_pllalock4:	/*	 * Restore master clock setting	 */	ldr	tmp1, .saved_mckr	str	tmp1, [pmc, #AT91_PMC_MCKR]	wait_mckrdy	mov	pc, lrENDPROC(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_sfddrc_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_sfddrc_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, lrENDPROC(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 0ENTRY(at91_pm_suspend_in_sram_sz)	.word .-at91_pm_suspend_in_sram
 |