arch/arm/mach-lpc32xx/suspend.S

Source file repositories/reference/linux-study-clean/arch/arm/mach-lpc32xx/suspend.S

File Facts

System
Linux kernel
Corpus path
arch/arm/mach-lpc32xx/suspend.S
Extension
.S
Size
4783 bytes
Lines
149
Domain
Architecture Layer
Bucket
arch/arm
Inferred role
Architecture Layer: arch/arm
Status
atlas-only

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

#include <linux/linkage.h>
#include <asm/assembler.h>
#include "lpc32xx.h"

/* Using named register defines makes the code easier to follow */
#define WORK1_REG			r0
#define WORK2_REG			r1
#define SAVED_HCLK_DIV_REG		r2
#define SAVED_HCLK_PLL_REG		r3
#define SAVED_DRAM_CLKCTRL_REG		r4
#define SAVED_PWR_CTRL_REG		r5
#define CLKPWRBASE_REG			r6
#define EMCBASE_REG			r7

#define LPC32XX_EMC_STATUS_OFFS		0x04
#define LPC32XX_EMC_STATUS_BUSY		0x1
#define LPC32XX_EMC_STATUS_SELF_RFSH	0x4

#define LPC32XX_CLKPWR_PWR_CTRL_OFFS	0x44
#define LPC32XX_CLKPWR_HCLK_DIV_OFFS	0x40
#define LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS 0x58

#define CLKPWR_PCLK_DIV_MASK		0xFFFFFE7F

	.text

ENTRY(lpc32xx_sys_suspend)
	@ Save a copy of the used registers in IRAM, r0 is corrupted
	adr	r0, tmp_stack_end
	stmfd	r0!, {r3 - r7, sp, lr}

	@ Load a few common register addresses
	adr	WORK1_REG, reg_bases
	ldr	CLKPWRBASE_REG, [WORK1_REG, #0]
	ldr	EMCBASE_REG, [WORK1_REG, #4]

	ldr	SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
		#LPC32XX_CLKPWR_PWR_CTRL_OFFS]
	orr	WORK1_REG, SAVED_PWR_CTRL_REG, #LPC32XX_CLKPWR_SDRAM_SELF_RFSH

	@ Wait for SDRAM busy status to go busy and then idle
	@ This guarantees a small windows where DRAM isn't busy
1:
	ldr	WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
	and	WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
	cmp	WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
	bne	1b @ Branch while idle
2:
	ldr	WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
	and	WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
	cmp	WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
	beq	2b @ Branch until idle

	@ Setup self-refresh with support for manual exit of
	@ self-refresh mode
	str	WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
	orr	WORK2_REG, WORK1_REG, #LPC32XX_CLKPWR_UPD_SDRAM_SELF_RFSH
	str	WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
	str	WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]

	@ Wait for self-refresh acknowledge, clocks to the DRAM device
	@ will automatically stop on start of self-refresh
3:
	ldr	WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
	and	WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH
	cmp	WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH
	bne	3b @ Branch until self-refresh mode starts

	@ Enter direct-run mode from run mode
	bic	WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_SELECT_RUN_MODE

Annotation

Implementation Notes