Skip to content

Commit 60915c8

Browse files
scottwcpgnashif
authored andcommitted
soc : mec1501 : Deep and light sleep example
Created MEC1501 deep and light sleep example for MCHP MEC1501. Modifications were made to SoC, board, timer, and hello world sample program. Power management split into SoC power implementing the interface and device power for device specific logic. Signed-off-by: Scott Worley <[email protected]>
1 parent cba129a commit 60915c8

File tree

9 files changed

+438
-0
lines changed

9 files changed

+438
-0
lines changed

boards/arm/mec15xxevb_assy6853/Kconfig.defconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,15 @@ endif # SPI_XEC_QMSPI
134134

135135
endif # SPI
136136

137+
# power management stuff
138+
if SYS_POWER_MANAGEMENT
139+
140+
config SYS_PM_MIN_RESIDENCY_SLEEP_1
141+
default 1000
142+
143+
config SYS_PM_MIN_RESIDENCY_DEEP_SLEEP_1
144+
default 2000
145+
146+
endif # SYS_POWER_MANAGEMENT
147+
137148
endif # BOARD_MEC15XXEVB_ASSY6853

boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853_defconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@ CONFIG_I2C_INIT_PRIORITY=60
2424
CONFIG_ESPI=y
2525

2626
CONFIG_SPI=y
27+
28+
# power management stuff
29+
CONFIG_SOC_POWER_MANAGEMENT=y

boards/arm/mec15xxevb_assy6853/pinmux.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,14 @@ static int board_pinmux_init(struct device *dev)
295295
#endif /* DT_INST_0_MICROCHIP_XEC_QMSPI */
296296
#endif /* CONFIG_SPI_XEC_QMSPI */
297297

298+
#ifdef CONFIG_SYS_PM_DEBUG
299+
/*
300+
* Deep sleep testing: Enable TEST_CLK_OUT on GPIO_060 function 2.
301+
* TEST_CLK_OUT is the PLL 48MHz conditioned output.
302+
*/
303+
pinmux_pin_set(portb, MCHP_GPIO_060, MCHP_GPIO_CTRL_MUX_F2);
304+
#endif
305+
298306
return 0;
299307
}
300308

soc/arm/microchip_mec/mec1501/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@
77
zephyr_sources(
88
soc.c
99
)
10+
11+
zephyr_sources_ifdef(CONFIG_SYS_POWER_MANAGEMENT
12+
device_power.c
13+
power.c
14+
)

soc/arm/microchip_mec/mec1501/Kconfig.defconfig.mec1501hsz

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,26 @@ config SPI_XEC_QMSPI
8888

8989
endif # SPI
9090

91+
if SOC_POWER_MANAGEMENT
92+
93+
config SYS_POWER_MANAGEMENT
94+
default y
95+
96+
config SYS_POWER_SLEEP_STATES
97+
default y
98+
99+
config HAS_SYS_POWER_STATE_SLEEP_1
100+
default y
101+
102+
config SYS_POWER_DEEP_SLEEP_STATES
103+
default y
104+
105+
config HAS_SYS_POWER_STATE_DEEP_SLEEP_1
106+
default y
107+
108+
config DEVICE_POWER_MANAGEMENT
109+
default n
110+
111+
endif # SOC_POWER_MANAGEMENT
112+
91113
endif # SOC_MEC1501_HSZ

soc/arm/microchip_mec/mec1501/Kconfig.soc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ endchoice
1616
config RTOS_TIMER
1717
bool "MEC1501 RTOS timer"
1818

19+
config SOC_POWER_MANAGEMENT
20+
bool "MEC1501 Power Management"
21+
1922
config SOC_MEC1501_PROC_CLK_DIV
2023
int "PROC_CLK_DIV"
2124
default 1
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/*
2+
* Copyright (c) 2019 Microchip Technology Inc.
3+
* Copyright (c) 2016 Intel Corporation.
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#include <zephyr.h>
9+
#include <sys_io.h>
10+
#include <misc/__assert.h>
11+
#include <power.h>
12+
#include <soc.h>
13+
14+
/*
15+
* CPU will spin up to DEEP_SLEEP_WAIT_SPIN_CLK_REQ times
16+
* waiting for PCR CLK_REQ bits to clear except for the
17+
* CPU bit itself. This is not necessary as the sleep hardware
18+
* will wait for all CLK_REQ to clear once WFI has executed.
19+
* Once all CLK_REQ signals are clear the hardware will transition
20+
* to the low power state.
21+
*/
22+
/* #define DEEP_SLEEP_WAIT_ON_CLK_REQ_ENABLE */
23+
#define DEEP_SLEEP_WAIT_SPIN_CLK_REQ 1000
24+
25+
26+
/*
27+
* Some peripherals if enabled always assert their CLK_REQ bits.
28+
* For example, any peripheral with a clock generator such as
29+
* timers, counters, UART, etc. We save the enables for these
30+
* peripherals, disable them, and restore the enabled state upon
31+
* wake.
32+
*/
33+
#define DEEP_SLEEP_PERIPH_SAVE_RESTORE
34+
35+
36+
/*
37+
* Light sleep: PLL remains on. Fastest wake latency.
38+
*/
39+
void soc_lite_sleep_enable(void)
40+
{
41+
SCB->SCR &= ~(1ul << 2);
42+
PCR_REGS->SYS_SLP_CTRL = MCHP_PCR_SYS_SLP_LIGHT;
43+
}
44+
45+
/*
46+
* Deep sleep: PLL is turned off. Wake is fast. PLL requires
47+
* a minimum of 3ms to lock. During this time the main clock
48+
* will be ramping up from ~16 to 24 MHz.
49+
*/
50+
51+
#if defined(CONFIG_SYS_POWER_DEEP_SLEEP_STATES)
52+
53+
void soc_deep_sleep_enable(void)
54+
{
55+
SCB->SCR = (1ul << 2); /* Cortex-M4 SLEEPDEEP */
56+
PCR_REGS->SYS_SLP_CTRL = MCHP_PCR_SYS_SLP_HEAVY;
57+
}
58+
59+
void soc_deep_sleep_disable(void)
60+
{
61+
SCB->SCR &= ~(1ul << 2); /* disable Cortex-M4 SLEEPDEEP */
62+
}
63+
64+
65+
void soc_deep_sleep_wait_clk_idle(void)
66+
{
67+
#ifdef DEEP_SLEEP_WAIT_ON_CLK_REQ_ENABLE
68+
u32_t clkreq, cnt;
69+
70+
cnt = DEEP_SLEEP_WAIT_CLK_REQ;
71+
do {
72+
clkreq = PCR_REGS->CLK_REQ0 | PCR_REGS->CLK_REQ1
73+
| PCR_REGS->CLK_REQ2 | PCR_REGS->CLK_REQ3
74+
| PCR_REGS->CLK_REQ4;
75+
} while ((clkreq != (1ul << MCHP_PCR1_CPU_POS)) && (cnt-- != 0));
76+
#endif
77+
}
78+
79+
80+
/*
81+
* Allow peripherals connected to external masters to wake the PLL but not
82+
* the EC. Once the peripheral has serviced the external master the PLL
83+
* will be turned back off. For example, if the eSPI master requests eSPI
84+
* configuration information or state of virtual wires the EC doesn't need
85+
* to be involved. The hardware can power on the PLL long enough to service
86+
* the request and then turn the PLL back off. The SMBus and I2C peripherals
87+
* in slave mode can also make use of this feature.
88+
*/
89+
void soc_deep_sleep_non_wake_en(void)
90+
{
91+
#ifdef CONFIG_ESPI_XEC
92+
GIRQ22_REGS->SRC = 0xfffffffful;
93+
GIRQ22_REGS->EN_SET = (1ul << 9);
94+
#endif
95+
}
96+
97+
void soc_deep_sleep_non_wake_dis(void)
98+
{
99+
#ifdef CONFIG_ESPI_XEC
100+
GIRQ22_REGS->EN_CLR = 0xfffffffful;
101+
GIRQ22_REGS->SRC = 0xfffffffful;
102+
#endif
103+
}
104+
105+
/* Variables used to save various HW state */
106+
#ifdef DEEP_SLEEP_PERIPH_SAVE_RESTORE
107+
108+
static u32_t ecs[1];
109+
110+
static void deep_sleep_save_ecs(void)
111+
{
112+
ecs[0] = ECS_REGS->ETM_CTRL;
113+
ECS_REGS->ETM_CTRL = 0;
114+
}
115+
116+
struct ds_timer_info {
117+
uintptr_t addr;
118+
u32_t restore_mask;
119+
};
120+
121+
const struct ds_timer_info ds_timer_tbl[] = {
122+
{
123+
(uintptr_t)&B16TMR0_REGS->CTRL, 0
124+
},
125+
{
126+
(uintptr_t)&B16TMR1_REGS->CTRL, 0
127+
},
128+
{
129+
(uintptr_t)&B32TMR0_REGS->CTRL, 0
130+
},
131+
{
132+
(uintptr_t)&B32TMR1_REGS->CTRL, 0
133+
},
134+
{
135+
(uintptr_t)&CCT_REGS->CTRL,
136+
(MCHP_CCT_CTRL_COMP1_SET | MCHP_CCT_CTRL_COMP0_SET),
137+
},
138+
};
139+
#define NUM_DS_TIMER_ENTRIES \
140+
(sizeof(ds_timer_tbl) / sizeof(struct ds_timer_info))
141+
142+
143+
static u32_t timers[NUM_DS_TIMER_ENTRIES];
144+
static u8_t uart_activate[3];
145+
146+
static void deep_sleep_save_uarts(void)
147+
{
148+
uart_activate[0] = UART0_REGS->ACTV;
149+
UART0_REGS->ACTV = 0;
150+
uart_activate[1] = UART1_REGS->ACTV;
151+
UART1_REGS->ACTV = 0;
152+
uart_activate[2] = UART2_REGS->ACTV;
153+
UART2_REGS->ACTV = 0;
154+
}
155+
156+
static void deep_sleep_save_timers(void)
157+
{
158+
const struct ds_timer_info *p;
159+
u32_t i;
160+
161+
p = &ds_timer_tbl[0];
162+
for (i = 0; i < NUM_DS_TIMER_ENTRIES; i++) {
163+
timers[i] = REG32(p->addr);
164+
REG32(p->addr) = 0;
165+
p++;
166+
}
167+
}
168+
169+
static void deep_sleep_restore_ecs(void)
170+
{
171+
ECS_REGS->ETM_CTRL = ecs[0];
172+
}
173+
174+
static void deep_sleep_restore_uarts(void)
175+
{
176+
UART0_REGS->ACTV = uart_activate[0];
177+
UART1_REGS->ACTV = uart_activate[1];
178+
UART2_REGS->ACTV = uart_activate[2];
179+
}
180+
181+
static void deep_sleep_restore_timers(void)
182+
{
183+
const struct ds_timer_info *p;
184+
u32_t i;
185+
186+
p = &ds_timer_tbl[0];
187+
for (i = 0; i < NUM_DS_TIMER_ENTRIES; i++) {
188+
REG32(p->addr) = timers[i] & ~p->restore_mask;
189+
p++;
190+
}
191+
}
192+
193+
void soc_deep_sleep_periph_save(void)
194+
{
195+
deep_sleep_save_uarts();
196+
deep_sleep_save_ecs();
197+
deep_sleep_save_timers();
198+
}
199+
200+
void soc_deep_sleep_periph_restore(void)
201+
{
202+
deep_sleep_restore_ecs();
203+
deep_sleep_restore_uarts();
204+
deep_sleep_restore_timers();
205+
}
206+
207+
#else
208+
209+
void soc_deep_sleep_periph_save(void)
210+
{
211+
}
212+
213+
void soc_deep_sleep_periph_restore(void)
214+
{
215+
}
216+
217+
#endif /* DEEP_SLEEP_PERIPH_SAVE_RESTORE */
218+
219+
#endif /* CONFIG_SYS_POWER_DEEP_SLEEP_STATES */
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright (c) 2019 Microchip Technology Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef __DEVICE_POWER_H
8+
#define __DEVICE_POWER_H
9+
10+
#ifndef _ASMLANGUAGE
11+
12+
void soc_lite_sleep_enable(void);
13+
14+
#if defined(CONFIG_SYS_POWER_DEEP_SLEEP_STATES)
15+
void soc_deep_sleep_enable(void);
16+
void soc_deep_sleep_disable(void);
17+
void soc_deep_sleep_periph_save(void);
18+
void soc_deep_sleep_periph_restore(void);
19+
void soc_deep_sleep_wait_clk_idle(void);
20+
void soc_deep_sleep_non_wake_en(void);
21+
void soc_deep_sleep_non_wake_dis(void);
22+
#endif
23+
24+
#endif
25+
26+
#endif

0 commit comments

Comments
 (0)