2019-05-27 09:55:08 +03:00
/* SPDX-License-Identifier: GPL-2.0-or-later */
2014-01-17 07:39:05 +04:00
/ *
* Copyright 2 0 1 4 F r e e s c a l e S e m i c o n d u c t o r , I n c .
* /
# include < l i n u x / l i n k a g e . h >
2014-06-30 19:29:12 +04:00
# include < a s m / a s s e m b l e r . h >
2014-02-26 15:48:33 +04:00
# include < a s m / a s m - o f f s e t s . h >
2014-01-17 07:39:05 +04:00
# include < a s m / h a r d w a r e / c a c h e - l 2 x0 . h >
# include " h a r d w a r e . h "
/ *
* = = = = = = = = = = = = = = = = = = = = low l e v e l s u s p e n d = = = = = = = = = = = = = = = = = = = =
*
* Better t o f o l l o w b e l o w r u l e s t o u s e A R M r e g i s t e r s :
* r0 : pm_ i n f o s t r u c t u r e a d d r e s s ;
* r1 ~ r4 : f o r s a v i n g p m _ i n f o m e m b e r s ;
* r5 ~ r10 : f r e e r e g i s t e r s ;
* r11 : io b a s e a d d r e s s .
*
* suspend o c r a m s p a c e l a y o u t :
* = = = = = = = = = = = = = = = = = = = = = = = = high a d d r e s s = = = = = = = = = = = = = = = = = = = = = =
* .
* .
* .
* ^
* ^
* ^
* imx6 _ s u s p e n d c o d e
* PM_ I N F O s t r u c t u r e ( i m x6 _ c p u _ p m _ i n f o )
* = = = = = = = = = = = = = = = = = = = = = = = = low a d d r e s s = = = = = = = = = = = = = = = = = = = = = = =
* /
/ *
* Below o f f s e t s a r e b a s e d o n s t r u c t i m x6 _ c p u _ p m _ i n f o
* which d e f i n e d i n a r c h / a r m / m a c h - i m x / p m - i m x6 q . c , t h i s
* structure c o n t a i n s n e c e s s a r y p m i n f o f o r l o w l e v e l
* suspend r e l a t e d c o d e .
* /
# define P M _ I N F O _ P B A S E _ O F F S E T 0 x0
# define P M _ I N F O _ R E S U M E _ A D D R _ O F F S E T 0 x4
2014-09-17 07:11:45 +04:00
# define P M _ I N F O _ D D R _ T Y P E _ O F F S E T 0 x8
2014-01-17 07:39:05 +04:00
# define P M _ I N F O _ P M _ I N F O _ S I Z E _ O F F S E T 0 x C
# define P M _ I N F O _ M X 6 Q _ M M D C _ P _ O F F S E T 0 x10
# define P M _ I N F O _ M X 6 Q _ M M D C _ V _ O F F S E T 0 x14
# define P M _ I N F O _ M X 6 Q _ S R C _ P _ O F F S E T 0 x18
# define P M _ I N F O _ M X 6 Q _ S R C _ V _ O F F S E T 0 x1 C
# define P M _ I N F O _ M X 6 Q _ I O M U X C _ P _ O F F S E T 0 x20
# define P M _ I N F O _ M X 6 Q _ I O M U X C _ V _ O F F S E T 0 x24
# define P M _ I N F O _ M X 6 Q _ C C M _ P _ O F F S E T 0 x28
# define P M _ I N F O _ M X 6 Q _ C C M _ V _ O F F S E T 0 x2 C
# define P M _ I N F O _ M X 6 Q _ G P C _ P _ O F F S E T 0 x30
# define P M _ I N F O _ M X 6 Q _ G P C _ V _ O F F S E T 0 x34
# define P M _ I N F O _ M X 6 Q _ L 2 _ P _ O F F S E T 0 x38
# define P M _ I N F O _ M X 6 Q _ L 2 _ V _ O F F S E T 0 x3 C
# define P M _ I N F O _ M M D C _ I O _ N U M _ O F F S E T 0 x40
# define P M _ I N F O _ M M D C _ I O _ V A L _ O F F S E T 0 x44
# define M X 6 Q _ S R C _ G P R 1 0 x20
# define M X 6 Q _ S R C _ G P R 2 0 x24
# define M X 6 Q _ M M D C _ M A P S R 0 x40 4
2014-01-17 07:39:07 +04:00
# define M X 6 Q _ M M D C _ M P D G C T R L 0 0 x83 c
2014-01-17 07:39:05 +04:00
# define M X 6 Q _ G P C _ I M R 1 0 x08
# define M X 6 Q _ G P C _ I M R 2 0 x0 c
# define M X 6 Q _ G P C _ I M R 3 0 x10
# define M X 6 Q _ G P C _ I M R 4 0 x14
# define M X 6 Q _ C C M _ C C R 0 x0
.align 3
2021-01-11 18:17:04 +03:00
.arm
2014-01-17 07:39:05 +04:00
.macro sync_l2_cache
/* sync L2 cache to drain L2's buffers to DRAM. */
# ifdef C O N F I G _ C A C H E _ L 2 X 0
ldr r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ L 2 _ V _ O F F S E T ]
2015-08-04 20:48:37 +03:00
teq r11 , #0
beq 6 f
2014-01-17 07:39:05 +04:00
mov r6 , #0x0
str r6 , [ r11 , #L 2 X 0 _ C A C H E _ S Y N C ]
1 :
ldr r6 , [ r11 , #L 2 X 0 _ C A C H E _ S Y N C ]
ands r6 , r6 , #0x1
bne 1 b
2015-08-04 20:48:37 +03:00
6 :
2014-01-17 07:39:05 +04:00
# endif
.endm
.macro resume_mmdc
/* restore MMDC IO */
cmp r5 , #0x0
ldreq r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ I O M U X C _ V _ O F F S E T ]
ldrne r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ I O M U X C _ P _ O F F S E T ]
ldr r6 , [ r0 , #P M _ I N F O _ M M D C _ I O _ N U M _ O F F S E T ]
ldr r7 , =PM_INFO_MMDC_IO_VAL_OFFSET
add r7 , r7 , r0
1 :
ldr r8 , [ r7 ] , #0x4
ldr r9 , [ r7 ] , #0x4
str r9 , [ r11 , r8 ]
subs r6 , r6 , #0x1
bne 1 b
cmp r5 , #0x0
ldreq r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ M M D C _ V _ O F F S E T ]
ldrne r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ M M D C _ P _ O F F S E T ]
2014-09-17 07:11:45 +04:00
cmp r3 , #I M X _ D D R _ T Y P E _ L P D D R 2
2014-01-17 07:39:07 +04:00
bne 4 f
/* reset read FIFO, RST_RD_FIFO */
ldr r7 , =MX6Q_MMDC_MPDGCTRL0
ldr r6 , [ r11 , r7 ]
orr r6 , r6 , #( 1 < < 3 1 )
str r6 , [ r11 , r7 ]
2 :
ldr r6 , [ r11 , r7 ]
ands r6 , r6 , #( 1 < < 3 1 )
bne 2 b
/* reset FIFO a second time */
ldr r6 , [ r11 , r7 ]
orr r6 , r6 , #( 1 < < 3 1 )
str r6 , [ r11 , r7 ]
3 :
ldr r6 , [ r11 , r7 ]
ands r6 , r6 , #( 1 < < 3 1 )
bne 3 b
4 :
2014-01-17 07:39:05 +04:00
/* let DDR out of self-refresh */
ldr r7 , [ r11 , #M X 6 Q _ M M D C _ M A P S R ]
bic r7 , r7 , #( 1 < < 2 1 )
str r7 , [ r11 , #M X 6 Q _ M M D C _ M A P S R ]
2014-01-17 07:39:07 +04:00
5 :
2014-01-17 07:39:05 +04:00
ldr r7 , [ r11 , #M X 6 Q _ M M D C _ M A P S R ]
ands r7 , r7 , #( 1 < < 2 5 )
2014-01-17 07:39:07 +04:00
bne 5 b
2014-01-17 07:39:05 +04:00
/* enable DDR auto power saving */
ldr r7 , [ r11 , #M X 6 Q _ M M D C _ M A P S R ]
bic r7 , r7 , #0x1
str r7 , [ r11 , #M X 6 Q _ M M D C _ M A P S R ]
.endm
ENTRY( i m x6 _ s u s p e n d )
ldr r1 , [ r0 , #P M _ I N F O _ P B A S E _ O F F S E T ]
ldr r2 , [ r0 , #P M _ I N F O _ R E S U M E _ A D D R _ O F F S E T ]
2014-09-17 07:11:45 +04:00
ldr r3 , [ r0 , #P M _ I N F O _ D D R _ T Y P E _ O F F S E T ]
2014-01-17 07:39:05 +04:00
ldr r4 , [ r0 , #P M _ I N F O _ P M _ I N F O _ S I Z E _ O F F S E T ]
/ *
* counting t h e r e s u m e a d d r e s s i n i r a m
* to s e t i t i n S R C r e g i s t e r .
* /
ldr r6 , =imx6_suspend
ldr r7 , =resume
sub r7 , r7 , r6
add r8 , r1 , r4
add r9 , r8 , r7
/ *
* make s u r e T L B c o n t a i n t h e a d d r w e w a n t ,
* as w e w i l l a c c e s s t h e m a f t e r M M D C I O f l o a t e d .
* /
ldr r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ C C M _ V _ O F F S E T ]
ldr r6 , [ r11 , #0x0 ]
ldr r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ G P C _ V _ O F F S E T ]
ldr r6 , [ r11 , #0x0 ]
2014-07-26 06:33:03 +04:00
ldr r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ I O M U X C _ V _ O F F S E T ]
ldr r6 , [ r11 , #0x0 ]
2014-01-17 07:39:05 +04:00
/* use r11 to store the IO address */
ldr r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ S R C _ V _ O F F S E T ]
/* store physical resume addr and pm_info address. */
str r9 , [ r11 , #M X 6 Q _ S R C _ G P R 1 ]
str r1 , [ r11 , #M X 6 Q _ S R C _ G P R 2 ]
/* need to sync L2 cache before DSM. */
sync_ l 2 _ c a c h e
ldr r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ M M D C _ V _ O F F S E T ]
/ *
* put D D R e x p l i c i t l y i n t o s e l f - r e f r e s h a n d
* disable a u t o m a t i c p o w e r s a v i n g s .
* /
ldr r7 , [ r11 , #M X 6 Q _ M M D C _ M A P S R ]
orr r7 , r7 , #0x1
str r7 , [ r11 , #M X 6 Q _ M M D C _ M A P S R ]
/* make the DDR explicitly enter self-refresh. */
ldr r7 , [ r11 , #M X 6 Q _ M M D C _ M A P S R ]
orr r7 , r7 , #( 1 < < 2 1 )
str r7 , [ r11 , #M X 6 Q _ M M D C _ M A P S R ]
poll_dvfs_set :
ldr r7 , [ r11 , #M X 6 Q _ M M D C _ M A P S R ]
ands r7 , r7 , #( 1 < < 2 5 )
beq p o l l _ d v f s _ s e t
ldr r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ I O M U X C _ V _ O F F S E T ]
ldr r6 , =0x0
ldr r7 , [ r0 , #P M _ I N F O _ M M D C _ I O _ N U M _ O F F S E T ]
ldr r8 , =PM_INFO_MMDC_IO_VAL_OFFSET
add r8 , r8 , r0
2014-09-17 07:11:45 +04:00
/* LPDDR2's last 3 IOs need special setting */
cmp r3 , #I M X _ D D R _ T Y P E _ L P D D R 2
2014-01-17 07:39:07 +04:00
subeq r7 , r7 , #0x3
2014-01-17 07:39:05 +04:00
set_mmdc_io_lpm :
ldr r9 , [ r8 ] , #0x8
str r6 , [ r11 , r9 ]
subs r7 , r7 , #0x1
bne s e t _ m m d c _ i o _ l p m
2014-09-17 07:11:45 +04:00
cmp r3 , #I M X _ D D R _ T Y P E _ L P D D R 2
2014-01-17 07:39:07 +04:00
bne s e t _ m m d c _ i o _ l p m _ d o n e
ldr r6 , =0x1000
ldr r9 , [ r8 ] , #0x8
str r6 , [ r11 , r9 ]
ldr r9 , [ r8 ] , #0x8
str r6 , [ r11 , r9 ]
ldr r6 , =0x80000
ldr r9 , [ r8 ]
str r6 , [ r11 , r9 ]
set_mmdc_io_lpm_done :
2014-01-17 07:39:05 +04:00
/ *
* mask a l l G P C i n t e r r u p t s b e f o r e
* enabling t h e R B C c o u n t e r s t o
* avoid t h e c o u n t e r s t a r t i n g t o o
* early i f a n i n t e r u p t i s a l r e a d y
* pending.
* /
ldr r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ G P C _ V _ O F F S E T ]
ldr r6 , [ r11 , #M X 6 Q _ G P C _ I M R 1 ]
ldr r7 , [ r11 , #M X 6 Q _ G P C _ I M R 2 ]
ldr r8 , [ r11 , #M X 6 Q _ G P C _ I M R 3 ]
ldr r9 , [ r11 , #M X 6 Q _ G P C _ I M R 4 ]
ldr r10 , =0xffffffff
str r10 , [ r11 , #M X 6 Q _ G P C _ I M R 1 ]
str r10 , [ r11 , #M X 6 Q _ G P C _ I M R 2 ]
str r10 , [ r11 , #M X 6 Q _ G P C _ I M R 3 ]
str r10 , [ r11 , #M X 6 Q _ G P C _ I M R 4 ]
/ *
* enable t h e R B C b y p a s s c o u n t e r h e r e
* to h o l d o f f t h e i n t e r r u p t s . R B C c o u n t e r
* = 3 2 ( 1 ms) , M i n i m u m R B C d e l a y s h o u l d b e
* 4 0 0 us f o r t h e a n a l o g L D O s t o p o w e r d o w n .
* /
ldr r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ C C M _ V _ O F F S E T ]
ldr r10 , [ r11 , #M X 6 Q _ C C M _ C C R ]
bic r10 , r10 , #( 0x3f < < 2 1 )
orr r10 , r10 , #( 0x20 < < 2 1 )
str r10 , [ r11 , #M X 6 Q _ C C M _ C C R ]
/* enable the counter. */
ldr r10 , [ r11 , #M X 6 Q _ C C M _ C C R ]
orr r10 , r10 , #( 0x1 < < 2 7 )
str r10 , [ r11 , #M X 6 Q _ C C M _ C C R ]
/* unmask all the GPC interrupts. */
ldr r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ G P C _ V _ O F F S E T ]
str r6 , [ r11 , #M X 6 Q _ G P C _ I M R 1 ]
str r7 , [ r11 , #M X 6 Q _ G P C _ I M R 2 ]
str r8 , [ r11 , #M X 6 Q _ G P C _ I M R 3 ]
str r9 , [ r11 , #M X 6 Q _ G P C _ I M R 4 ]
/ *
* now d e l a y f o r a s h o r t w h i l e ( 3 u s e c )
* ARM i s a t 1 G H z a t t h i s p o i n t
* so a s h o r t l o o p s h o u l d b e e n o u g h .
* this d e l a y i s r e q u i r e d t o e n s u r e t h a t
* the R B C c o u n t e r c a n s t a r t c o u n t i n g i n
* case a n i n t e r r u p t i s a l r e a d y p e n d i n g
* or i n c a s e a n i n t e r r u p t a r r i v e s j u s t
* as A R M i s a b o u t t o a s s e r t D S M _ r e q u e s t .
* /
ldr r6 , =2000
rbc_loop :
subs r6 , r6 , #0x1
bne r b c _ l o o p
/* Zzz, enter stop mode */
wfi
nop
nop
nop
nop
/ *
* run t o h e r e m e a n s t h e r e i s p e n d i n g
* wakeup s o u r c e , s y s t e m s h o u l d a u t o
* resume, w e n e e d t o r e s t o r e M M D C I O f i r s t
* /
mov r5 , #0x0
resume_ m m d c
/* return to suspend finish */
2014-06-30 19:29:12 +04:00
ret l r
2014-01-17 07:39:05 +04:00
resume :
/* invalidate L1 I-cache first */
mov r6 , #0x0
mcr p15 , 0 , r6 , c7 , c5 , 0
mcr p15 , 0 , r6 , c7 , c5 , 6
/* enable the Icache and branch prediction */
mov r6 , #0x1800
mcr p15 , 0 , r6 , c1 , c0 , 0
isb
/* get physical resume address from pm_info. */
ldr l r , [ r0 , #P M _ I N F O _ R E S U M E _ A D D R _ O F F S E T ]
/* clear core0's entry and parameter */
ldr r11 , [ r0 , #P M _ I N F O _ M X 6 Q _ S R C _ P _ O F F S E T ]
mov r7 , #0x0
str r7 , [ r11 , #M X 6 Q _ S R C _ G P R 1 ]
str r7 , [ r11 , #M X 6 Q _ S R C _ G P R 2 ]
2014-09-17 07:11:45 +04:00
ldr r3 , [ r0 , #P M _ I N F O _ D D R _ T Y P E _ O F F S E T ]
2014-01-17 07:39:05 +04:00
mov r5 , #0x1
resume_ m m d c
2014-06-30 19:29:12 +04:00
ret l r
2014-01-17 07:39:05 +04:00
ENDPROC( i m x6 _ s u s p e n d )