Skip to content

Commit c9b34b7

Browse files
wenyouyaclaudiubeznea
authored andcommitted
ARM: at91: pm: Add ULP1 mode support
In the ULP1 mode, in order to achieve the lowest power consumption with the system in retention mode and be able to resume on the wake up events, all the clocks are shut off, inclusive the embedded 12MHz RC oscillator, and the number of wake up sources is limited as well. When the wake up event is asserted, the embedded 12MHz RC oscillator restarts automatically. The ULP1 (Ultra Low-power mode 1) is introduced by SAMA5D2. Signed-off-by: Wenyou Yang <wenyou.yang@atmel.com> Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com> [claudiu.beznea@microchip.com: aligned with 4.14 and Linux4Sam5.7 changes] Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
1 parent d87efae commit c9b34b7

4 files changed

Lines changed: 127 additions & 21 deletions

File tree

arch/arm/mach-at91/pm.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ extern void at91_pinctrl_gpio_resume(void);
4242
static const match_table_t pm_modes __initconst = {
4343
{ AT91_PM_STANDBY, "standby" },
4444
{ AT91_PM_ULP0, "ulp0" },
45+
{ AT91_PM_ULP1, "ulp1" },
4546
{ AT91_PM_BACKUP, "backup" },
4647
{ -1, NULL },
4748
};

arch/arm/mach-at91/pm.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323

2424
#define AT91_PM_STANDBY 0x00
2525
#define AT91_PM_ULP0 0x01
26-
#define AT91_PM_BACKUP 0x02
26+
#define AT91_PM_ULP1 0x02
27+
#define AT91_PM_BACKUP 0x03
2728

2829
#ifndef __ASSEMBLY__
2930
struct at91_pm_data {

arch/arm/mach-at91/pm_suspend.S

Lines changed: 122 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ tmp2 .req r5
4141
beq 1b
4242
.endm
4343

44+
/*
45+
* Wait for main oscillator selection is done
46+
*/
47+
.macro wait_moscsels
48+
1: ldr tmp1, [pmc, #AT91_PMC_SR]
49+
tst tmp1, #AT91_PMC_MOSCSELS
50+
beq 1b
51+
.endm
52+
4453
/*
4554
* Wait until PLLA has locked.
4655
*/
@@ -112,19 +121,20 @@ ENTRY(at91_pm_suspend_in_sram)
112121
bl at91_sramc_self_refresh
113122

114123
ldr r0, .pm_mode
115-
cmp r0, #AT91_PM_ULP0
116-
beq ulp0_mode
124+
cmp r0, #AT91_PM_STANDBY
125+
beq standby
117126
cmp r0, #AT91_PM_BACKUP
118127
beq backup_mode
119128

129+
bl at91_ulp_mode
130+
b exit_suspend
131+
132+
standby:
120133
/* Wait for interrupt */
121134
ldr pmc, .pmc_base
122135
at91_cpu_idle
123136
b exit_suspend
124137

125-
ulp0_mode:
126-
bl at91_ulp0_mode
127-
b exit_suspend
128138
backup_mode:
129139
bl at91_backup_mode
130140
b exit_suspend
@@ -151,7 +161,102 @@ ENTRY(at91_backup_mode)
151161
str tmp1, [r0, #0]
152162
ENDPROC(at91_backup_mode)
153163

154-
ENTRY(at91_ulp0_mode)
164+
.macro at91_pm_ulp0_mode
165+
ldr pmc, .pmc_base
166+
167+
/* Turn off the crystal oscillator */
168+
ldr tmp1, [pmc, #AT91_CKGR_MOR]
169+
bic tmp1, tmp1, #AT91_PMC_MOSCEN
170+
orr tmp1, tmp1, #AT91_PMC_KEY
171+
str tmp1, [pmc, #AT91_CKGR_MOR]
172+
173+
/* Wait for interrupt */
174+
at91_cpu_idle
175+
176+
/* Turn on the crystal oscillator */
177+
ldr tmp1, [pmc, #AT91_CKGR_MOR]
178+
orr tmp1, tmp1, #AT91_PMC_MOSCEN
179+
orr tmp1, tmp1, #AT91_PMC_KEY
180+
str tmp1, [pmc, #AT91_CKGR_MOR]
181+
182+
wait_moscrdy
183+
.endm
184+
185+
/**
186+
* Note: This procedure only applies on the platform which uses
187+
* the external crystal oscillator as a main clock source.
188+
*/
189+
.macro at91_pm_ulp1_mode
190+
ldr pmc, .pmc_base
191+
192+
/* Switch the main clock source to 12-MHz RC oscillator */
193+
ldr tmp1, [pmc, #AT91_CKGR_MOR]
194+
bic tmp1, tmp1, #AT91_PMC_MOSCSEL
195+
bic tmp1, tmp1, #AT91_PMC_KEY_MASK
196+
orr tmp1, tmp1, #AT91_PMC_KEY
197+
str tmp1, [pmc, #AT91_CKGR_MOR]
198+
199+
wait_moscsels
200+
201+
/* Disable the crystal oscillator */
202+
ldr tmp1, [pmc, #AT91_CKGR_MOR]
203+
bic tmp1, tmp1, #AT91_PMC_MOSCEN
204+
bic tmp1, tmp1, #AT91_PMC_KEY_MASK
205+
orr tmp1, tmp1, #AT91_PMC_KEY
206+
str tmp1, [pmc, #AT91_CKGR_MOR]
207+
208+
/* Switch the master clock source to main clock */
209+
ldr tmp1, [pmc, #AT91_PMC_MCKR]
210+
bic tmp1, tmp1, #AT91_PMC_CSS
211+
orr tmp1, tmp1, #AT91_PMC_CSS_MAIN
212+
str tmp1, [pmc, #AT91_PMC_MCKR]
213+
214+
wait_mckrdy
215+
216+
/* Enter the ULP1 mode by set WAITMODE bit in CKGR_MOR */
217+
ldr tmp1, [pmc, #AT91_CKGR_MOR]
218+
orr tmp1, tmp1, #AT91_PMC_WAITMODE
219+
bic tmp1, tmp1, #AT91_PMC_KEY_MASK
220+
orr tmp1, tmp1, #AT91_PMC_KEY
221+
str tmp1, [pmc, #AT91_CKGR_MOR]
222+
223+
wait_mckrdy
224+
225+
/* Enable the crystal oscillator */
226+
ldr tmp1, [pmc, #AT91_CKGR_MOR]
227+
orr tmp1, tmp1, #AT91_PMC_MOSCEN
228+
bic tmp1, tmp1, #AT91_PMC_KEY_MASK
229+
orr tmp1, tmp1, #AT91_PMC_KEY
230+
str tmp1, [pmc, #AT91_CKGR_MOR]
231+
232+
wait_moscrdy
233+
234+
/* Switch the master clock source to slow clock */
235+
ldr tmp1, [pmc, #AT91_PMC_MCKR]
236+
bic tmp1, tmp1, #AT91_PMC_CSS
237+
str tmp1, [pmc, #AT91_PMC_MCKR]
238+
239+
wait_mckrdy
240+
241+
/* Switch main clock source to crystal oscillator */
242+
ldr tmp1, [pmc, #AT91_CKGR_MOR]
243+
orr tmp1, tmp1, #AT91_PMC_MOSCSEL
244+
bic tmp1, tmp1, #AT91_PMC_KEY_MASK
245+
orr tmp1, tmp1, #AT91_PMC_KEY
246+
str tmp1, [pmc, #AT91_CKGR_MOR]
247+
248+
wait_moscsels
249+
250+
/* Switch the master clock source to main clock */
251+
ldr tmp1, [pmc, #AT91_PMC_MCKR]
252+
bic tmp1, tmp1, #AT91_PMC_CSS
253+
orr tmp1, tmp1, #AT91_PMC_CSS_MAIN
254+
str tmp1, [pmc, #AT91_PMC_MCKR]
255+
256+
wait_mckrdy
257+
.endm
258+
259+
ENTRY(at91_ulp_mode)
155260
ldr pmc, .pmc_base
156261

157262
/* Save Master clock setting */
@@ -174,22 +279,19 @@ ENTRY(at91_ulp0_mode)
174279
orr tmp1, tmp1, #(1 << 29) /* bit 29 always set */
175280
str tmp1, [pmc, #AT91_CKGR_PLLAR]
176281

177-
/* Turn off the main oscillator */
178-
ldr tmp1, [pmc, #AT91_CKGR_MOR]
179-
bic tmp1, tmp1, #AT91_PMC_MOSCEN
180-
orr tmp1, tmp1, #AT91_PMC_KEY
181-
str tmp1, [pmc, #AT91_CKGR_MOR]
282+
ldr r0, .pm_mode
283+
cmp r0, #AT91_PM_ULP1
284+
beq ulp1_mode
182285

183-
/* Wait for interrupt */
184-
at91_cpu_idle
286+
at91_pm_ulp0_mode
287+
b ulp_exit
185288

186-
/* Turn on the main oscillator */
187-
ldr tmp1, [pmc, #AT91_CKGR_MOR]
188-
orr tmp1, tmp1, #AT91_PMC_MOSCEN
189-
orr tmp1, tmp1, #AT91_PMC_KEY
190-
str tmp1, [pmc, #AT91_CKGR_MOR]
289+
ulp1_mode:
290+
at91_pm_ulp1_mode
291+
b ulp_exit
191292

192-
wait_moscrdy
293+
ulp_exit:
294+
ldr pmc, .pmc_base
193295

194296
/* Restore PLLA setting */
195297
ldr tmp1, .saved_pllar
@@ -212,7 +314,7 @@ ENTRY(at91_ulp0_mode)
212314
wait_mckrdy
213315

214316
mov pc, lr
215-
ENDPROC(at91_ulp0_mode)
317+
ENDPROC(at91_ulp_mode)
216318

217319
/*
218320
* void at91_sramc_self_refresh(unsigned int is_active)

include/linux/clk/at91_pmc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@
4747
#define AT91_CKGR_MOR 0x20 /* Main Oscillator Register [not on SAM9RL] */
4848
#define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */
4949
#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass */
50+
#define AT91_PMC_WAITMODE (1 << 2) /* Wait Mode Command */
5051
#define AT91_PMC_MOSCRCEN (1 << 3) /* Main On-Chip RC Oscillator Enable [some SAM9] */
5152
#define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */
53+
#define AT91_PMC_KEY_MASK (0xff << 16)
5254
#define AT91_PMC_KEY (0x37 << 16) /* MOR Writing Key */
5355
#define AT91_PMC_MOSCSEL (1 << 24) /* Main Oscillator Selection [some SAM9] */
5456
#define AT91_PMC_CFDEN (1 << 25) /* Clock Failure Detector Enable [some SAM9] */

0 commit comments

Comments
 (0)