2010-07-27 08:35:56 -07:00
/ *
* arch/ a r m / m a c h - l p c32 x x / s u s p e n d . S
*
* Original a u t h o r s : D m i t r y C h i g i r e v , V i t a l y W o o l < s o u r c e @mvista.com>
* Modified b y K e v i n W e l l s < k e v i n . w e l l s @nxp.com>
*
* 2 0 0 5 ( c) M o n t a V i s t a S o f t w a r e , I n c . T h i s f i l e i s l i c e n s e d u n d e r
* the t e r m s o f t h e G N U G e n e r a l P u b l i c L i c e n s e v e r s i o n 2 . T h i s p r o g r a m
* is l i c e n s e d " a s i s " w i t h o u t a n y w a r r a n t y o f a n y k i n d , w h e t h e r e x p r e s s
* or i m p l i e d .
* /
# include < l i n u x / l i n k a g e . h >
# include < a s m / a s s e m b l e r . h >
2019-08-09 16:40:38 +02:00
# include " l p c32 x x . h "
2010-07-27 08:35:56 -07:00
/* Using named register defines makes the code easier to follow */
# define W O R K 1 _ R E G r0
# define W O R K 2 _ R E G r1
# define S A V E D _ H C L K _ D I V _ R E G r2
# define S A V E D _ H C L K _ P L L _ R E G r3
# define S A V E D _ D R A M _ C L K C T R L _ R E G r4
# define S A V E D _ P W R _ C T R L _ R E G r5
# define C L K P W R B A S E _ R E G r6
# define E M C B A S E _ R E G r7
# define L P C 3 2 X X _ E M C _ S T A T U S _ O F F S 0 x04
# define L P C 3 2 X X _ E M C _ S T A T U S _ B U S Y 0 x1
# define L P C 3 2 X X _ E M C _ S T A T U S _ S E L F _ R F S H 0 x4
# define L P C 3 2 X X _ C L K P W R _ P W R _ C T R L _ O F F S 0 x44
# define L P C 3 2 X X _ C L K P W R _ H C L K _ D I V _ O F F S 0 x40
# define L P C 3 2 X X _ C L K P W R _ H C L K P L L _ C T R L _ O F F S 0 x58
# define C L K P W R _ P C L K _ D I V _ M A S K 0 x F F F F F E 7 F
.text
ENTRY( l p c32 x x _ s y s _ s u s p e n d )
@ Save a copy of the used registers in IRAM, r0 is corrupted
adr r0 , t m p _ s t a c k _ e n d
stmfd r0 ! , { r3 - r7 , s p , l r }
@ Load a few common register addresses
adr W O R K 1 _ R E G , r e g _ b a s e s
ldr C L K P W R B A S E _ R E G , [ W O R K 1 _ R E G , #0 ]
ldr E M C B A S E _ R E G , [ W O R K 1 _ R E G , #4 ]
ldr S A V E D _ P W R _ C T R L _ R E G , [ C L K P W R B A S E _ R E G ,\
# LPC3 2 X X _ C L K P W R _ P W R _ C T R L _ O F F S ]
orr W O R K 1 _ R E G , S A V E D _ P W R _ C T R L _ R E G , #L P C 32 X X _ C L K P W R _ S D R A M _ S E L F _ R F S H
@ Wait for SDRAM busy status to go busy and then idle
@ This guarantees a small windows where DRAM isn't busy
1 :
ldr W O R K 2 _ R E G , [ E M C B A S E _ R E G , #L P C 32 X X _ E M C _ S T A T U S _ O F F S ]
and W O R K 2 _ R E G , W O R K 2 _ R E G , #L P C 32 X X _ E M C _ S T A T U S _ B U S Y
cmp W O R K 2 _ R E G , #L P C 32 X X _ E M C _ S T A T U S _ B U S Y
bne 1 b @ Branch while idle
2 :
ldr W O R K 2 _ R E G , [ E M C B A S E _ R E G , #L P C 32 X X _ E M C _ S T A T U S _ O F F S ]
and W O R K 2 _ R E G , W O R K 2 _ R E G , #L P C 32 X X _ E M C _ S T A T U S _ B U S Y
cmp W O R K 2 _ R E G , #L P C 32 X X _ E M C _ S T A T U S _ B U S Y
beq 2 b @ Branch until idle
@ Setup self-refresh with support for manual exit of
@ self-refresh mode
str W O R K 1 _ R E G , [ C L K P W R B A S E _ R E G , #L P C 32 X X _ C L K P W R _ P W R _ C T R L _ O F F S ]
orr W O R K 2 _ R E G , W O R K 1 _ R E G , #L P C 32 X X _ C L K P W R _ U P D _ S D R A M _ S E L F _ R F S H
str W O R K 2 _ R E G , [ C L K P W R B A S E _ R E G , #L P C 32 X X _ C L K P W R _ P W R _ C T R L _ O F F S ]
str W O R K 1 _ R E G , [ C L K P W R B A S E _ R E G , #L P C 32 X X _ C L K P W R _ P W R _ C T R L _ O F F S ]
@ Wait for self-refresh acknowledge, clocks to the DRAM device
@ will automatically stop on start of self-refresh
3 :
ldr W O R K 2 _ R E G , [ E M C B A S E _ R E G , #L P C 32 X X _ E M C _ S T A T U S _ O F F S ]
and W O R K 2 _ R E G , W O R K 2 _ R E G , #L P C 32 X X _ E M C _ S T A T U S _ S E L F _ R F S H
cmp W O R K 2 _ R E G , #L P C 32 X X _ E M C _ S T A T U S _ S E L F _ R F S H
bne 3 b @ Branch until self-refresh mode starts
@ Enter direct-run mode from run mode
bic W O R K 1 _ R E G , W O R K 1 _ R E G , #L P C 32 X X _ C L K P W R _ S E L E C T _ R U N _ M O D E
str W O R K 1 _ R E G , [ C L K P W R B A S E _ R E G , #L P C 32 X X _ C L K P W R _ P W R _ C T R L _ O F F S ]
@ Safe disable of DRAM clock in EMC block, prevents DDR sync
@ issues on restart
ldr S A V E D _ H C L K _ D I V _ R E G , [ C L K P W R B A S E _ R E G ,\
# LPC3 2 X X _ C L K P W R _ H C L K _ D I V _ O F F S ]
and W O R K 2 _ R E G , S A V E D _ H C L K _ D I V _ R E G , #C L K P W R _ P C L K _ D I V _ M A S K
str W O R K 2 _ R E G , [ C L K P W R B A S E _ R E G , #L P C 32 X X _ C L K P W R _ H C L K _ D I V _ O F F S ]
@ Save HCLK PLL state and disable HCLK PLL
ldr S A V E D _ H C L K _ P L L _ R E G , [ C L K P W R B A S E _ R E G ,\
# LPC3 2 X X _ C L K P W R _ H C L K P L L _ C T R L _ O F F S ]
bic W O R K 2 _ R E G , S A V E D _ H C L K _ P L L _ R E G , #L P C 32 X X _ C L K P W R _ H C L K P L L _ P O W E R _ U P
str W O R K 2 _ R E G , [ C L K P W R B A S E _ R E G , #L P C 32 X X _ C L K P W R _ H C L K P L L _ C T R L _ O F F S ]
@ Enter stop mode until an enabled event occurs
orr W O R K 1 _ R E G , W O R K 1 _ R E G , #L P C 32 X X _ C L K P W R _ S T O P _ M O D E _ C T R L
str W O R K 1 _ R E G , [ C L K P W R B A S E _ R E G , #L P C 32 X X _ C L K P W R _ P W R _ C T R L _ O F F S ]
.rept 9
nop
.endr
@ Clear stop status
bic W O R K 1 _ R E G , W O R K 1 _ R E G , #L P C 32 X X _ C L K P W R _ S T O P _ M O D E _ C T R L
@ Restore original HCLK PLL value and wait for PLL lock
str S A V E D _ H C L K _ P L L _ R E G , [ C L K P W R B A S E _ R E G ,\
# LPC3 2 X X _ C L K P W R _ H C L K P L L _ C T R L _ O F F S ]
4 :
ldr W O R K 2 _ R E G , [ C L K P W R B A S E _ R E G , #L P C 32 X X _ C L K P W R _ H C L K P L L _ C T R L _ O F F S ]
and W O R K 2 _ R E G , W O R K 2 _ R E G , #L P C 32 X X _ C L K P W R _ H C L K P L L _ P L L _ S T S
bne 4 b
@ Re-enter run mode with self-refresh flag cleared, but no DRAM
@ update yet. DRAM is still in self-refresh
str S A V E D _ P W R _ C T R L _ R E G , [ C L K P W R B A S E _ R E G ,\
# LPC3 2 X X _ C L K P W R _ P W R _ C T R L _ O F F S ]
@ Restore original DRAM clock mode to restore DRAM clocks
str S A V E D _ H C L K _ D I V _ R E G , [ C L K P W R B A S E _ R E G ,\
# LPC3 2 X X _ C L K P W R _ H C L K _ D I V _ O F F S ]
@ Clear self-refresh mode
orr W O R K 1 _ R E G , S A V E D _ P W R _ C T R L _ R E G ,\
# LPC3 2 X X _ C L K P W R _ U P D _ S D R A M _ S E L F _ R F S H
str W O R K 1 _ R E G , [ C L K P W R B A S E _ R E G , #L P C 32 X X _ C L K P W R _ P W R _ C T R L _ O F F S ]
str S A V E D _ P W R _ C T R L _ R E G , [ C L K P W R B A S E _ R E G ,\
# LPC3 2 X X _ C L K P W R _ P W R _ C T R L _ O F F S ]
@ Wait for EMC to clear self-refresh mode
5 :
ldr W O R K 2 _ R E G , [ E M C B A S E _ R E G , #L P C 32 X X _ E M C _ S T A T U S _ O F F S ]
and W O R K 2 _ R E G , W O R K 2 _ R E G , #L P C 32 X X _ E M C _ S T A T U S _ S E L F _ R F S H
bne 5 b @ Branch until self-refresh has exited
@ restore regs and return
adr r0 , t m p _ s t a c k
ldmfd r0 ! , { r3 - r7 , s p , p c }
reg_bases :
.long IO_ A D D R E S S ( L P C 3 2 X X _ C L K _ P M _ B A S E )
.long IO_ A D D R E S S ( L P C 3 2 X X _ E M C _ B A S E )
tmp_stack :
.long 0 , 0 , 0 , 0 , 0 , 0 , 0
tmp_stack_end :
ENTRY( l p c32 x x _ s y s _ s u s p e n d _ s z )
.word . - lpc3 2 x x _ s y s _ s u s p e n d