1 /*
2  * Copyright (c) 2021 Nuvoton Technology Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Nuvoton NPCX power management driver
10  *
11  * This file contains the drivers of NPCX Power Manager Modules that improves
12  * the efficiency of ec operation by adjusting the chip’s power consumption to
13  * the level of activity required by the application. The following table
14  * summarizes the main properties of the various power states and shows the
15  * activity levels of the various clocks while in these power states.
16  *
17  * +--------------------------------------------------------------------------+
18  * | Power State | LFCLK | HFCLK | APB/AHB |  Core  | RAM/Regs   | VCC | VSBY |
19  * |--------------------------------------------------------------------------|
20  * | Active      | On    | On    | On      | Active | Active     | On  | On   |
21  * | Idle (wfi)  | On    | On    | On      | Wait   | Active     | On  | On   |
22  * | Sleep       | On    | On    | Stop    | Stop   | Preserved  | On  | On   |
23  * | Deep Sleep  | On    | Stop  | Stop    | Stop   | Power Down | On  | On   |
24  * | Stand-By    | Off   | Off   | Off     | Off    | Off        | Off | On   |
25  * +--------------------------------------------------------------------------+
26  *
27  * LFCLK - Low-Frequency Clock. Its frequency is fixed to 32kHz.
28  * HFCLK - High-Frequency (PLL) Clock. Its frequency is configured to OFMCLK.
29  *
30  * Based on the follwoing criteria:
31  *
32  * - A delay of 'Instant' wake-up from 'Deep Sleep' is 20 us.
33  * - A delay of 'Standard' wake-up from 'Deep Sleep' is 3.43 ms.
34  * - Max residency time in Deep Sleep for 'Instant' wake-up is 200 ms
35  * - Min Residency time in Deep Sleep for 'Instant' wake-up is 61 us
36  * - The unit to determine power state residency policy is tick.
37  *
38  * this driver implements one power state, PM_STATE_SUSPEND_TO_IDLE, with
39  * two sub-states for power management system.
40  * Sub-state 0 - "Deep Sleep" mode with “Instant” wake-up if residency time
41  *               is greater or equal to 1 ms
42  * Sub-state 1 - "Deep Sleep" mode with "Standard" wake-up if residency time
43  *               is greater or equal to 201 ms
44  *
45  * INCLUDE FILES: soc_clock.h
46  */
47 
48 #include <arch/arm/aarch32/cortex_m/cmsis.h>
49 #include <zephyr.h>
50 #include <drivers/espi.h>
51 #include <pm/pm.h>
52 #include <soc.h>
53 
54 #include "soc_host.h"
55 #include "soc_power.h"
56 
57 #include <logging/log.h>
58 LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
59 
60 /* The steps that npcx ec enters sleep/deep mode and leaves it. */
61 #define NPCX_ENTER_SYSTEM_SLEEP() ({                                           \
62 	__asm__ volatile (                                                     \
63 	"push {r0-r5}\n"     /* Save the registers used for delay */           \
64 	"wfi\n"              /* Enter sleep mode after receiving wfi */        \
65 	"ldm %0, {r0-r5}\n"  /* Add a delay before instructions fetching */    \
66 	"pop {r0-r5}\n"      /* Restore the registers used for delay */        \
67 	"isb\n"              /* Flush the cpu pipelines */                     \
68 	:: "r" (CONFIG_SRAM_BASE_ADDRESS)); /* A valid addr used for delay */  \
69 	})
70 
71 /* Variables for tracing */
72 static uint32_t cnt_sleep0;
73 static uint32_t cnt_sleep1;
74 
75 /* Supported sleep mode in npcx series */
76 enum {
77 	NPCX_SLEEP,
78 	NPCX_DEEP_SLEEP,
79 };
80 
81 /* Supported wake-up mode in npcx series */
82 enum {
83 	NPCX_INSTANT_WAKE_UP,
84 	NPCX_STANDARD_WAKE_UP,
85 };
86 
87 #ifdef CONFIG_UART_CONSOLE_INPUT_EXPIRED
88 static int64_t expired_timeout = CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT;
89 static int64_t console_expired_time = CONFIG_UART_CONSOLE_INPUT_EXPIRED_TIMEOUT;
90 
91 /* Platform specific power control functions */
npcx_power_console_is_in_use(void)92 bool npcx_power_console_is_in_use(void)
93 {
94 	return (k_uptime_get() < console_expired_time);
95 }
96 
npcx_power_console_is_in_use_refresh(void)97 void npcx_power_console_is_in_use_refresh(void)
98 {
99 	console_expired_time = k_uptime_get() + expired_timeout;
100 }
101 
npcx_power_set_console_in_use_timeout(int64_t timeout)102 void npcx_power_set_console_in_use_timeout(int64_t timeout)
103 {
104 	expired_timeout = timeout;
105 }
106 #endif
107 
npcx_power_enter_system_sleep(int slp_mode,int wk_mode)108 static void npcx_power_enter_system_sleep(int slp_mode, int wk_mode)
109 {
110 	/* Disable interrupts */
111 	__disable_irq();
112 
113 	/*
114 	 * Disable priority mask temporarily to make sure that wake-up events
115 	 * are visible to the WFI instruction.
116 	 */
117 	__set_BASEPRI(0);
118 
119 	/* Configure sleep/deep sleep settings in clock control module. */
120 	npcx_clock_control_turn_on_system_sleep(slp_mode == NPCX_DEEP_SLEEP,
121 					wk_mode == NPCX_INSTANT_WAKE_UP);
122 
123 	/* A bypass in npcx7 series to prevent leakage in low-voltage pads */
124 	if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) {
125 		npcx_lvol_suspend_io_pads();
126 	}
127 
128 	/* Turn on eSPI/LPC host access wake-up interrupt. */
129 	if (IS_ENABLED(CONFIG_ESPI_NPCX)) {
130 		npcx_host_enable_access_interrupt();
131 	}
132 
133 	/* Turn on UART RX wake-up interrupt. */
134 	if (IS_ENABLED(CONFIG_UART_NPCX)) {
135 		npcx_uart_enable_access_interrupt();
136 	}
137 
138 	/*
139 	 * Capture the reading of low-freq timer for compensation before ec
140 	 * enters system sleep mode.
141 	 */
142 	npcx_clock_capture_low_freq_timer();
143 
144 	/* Enter system sleep mode */
145 	NPCX_ENTER_SYSTEM_SLEEP();
146 
147 	/*
148 	 * Compensate system timer by the elasped time of low-freq timer during
149 	 * system sleep mode.
150 	 */
151 	npcx_clock_compensate_system_timer();
152 
153 	/* Turn off eSPI/LPC host access wake-up interrupt. */
154 	if (IS_ENABLED(CONFIG_ESPI_NPCX)) {
155 		npcx_host_disable_access_interrupt();
156 	}
157 
158 	/* A bypass in npcx7 series to prevent leakage in low-voltage pads */
159 	if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) {
160 		npcx_lvol_restore_io_pads();
161 	}
162 
163 	/* Turn off system sleep mode. */
164 	npcx_clock_control_turn_off_system_sleep();
165 }
166 
167 /* Invoke when enter "Suspend/Low Power" mode. */
pm_power_state_set(struct pm_state_info info)168 __weak void pm_power_state_set(struct pm_state_info info)
169 {
170 	if (info.state != PM_STATE_SUSPEND_TO_IDLE) {
171 		LOG_DBG("Unsupported power state %u", info.state);
172 	} else {
173 		switch (info.substate_id) {
174 		case 0:	/* Sub-state 0: Deep sleep with instant wake-up */
175 			npcx_power_enter_system_sleep(NPCX_DEEP_SLEEP,
176 							NPCX_INSTANT_WAKE_UP);
177 			if (IS_ENABLED(CONFIG_SOC_POWER_MANAGEMENT_TRACE)) {
178 				cnt_sleep0++;
179 			}
180 			break;
181 		case 1:	/* Sub-state 1: Deep sleep with standard wake-up */
182 			npcx_power_enter_system_sleep(NPCX_DEEP_SLEEP,
183 							NPCX_STANDARD_WAKE_UP);
184 			if (IS_ENABLED(CONFIG_SOC_POWER_MANAGEMENT_TRACE)) {
185 				cnt_sleep1++;
186 			}
187 			break;
188 		default:
189 			LOG_DBG("Unsupported power substate-id %u",
190 				info.substate_id);
191 			break;
192 		}
193 	}
194 }
195 
196 /* Handle soc specific activity after exiting "Suspend/Low Power" mode. */
pm_power_state_exit_post_ops(struct pm_state_info info)197 __weak void pm_power_state_exit_post_ops(struct pm_state_info info)
198 {
199 	if (info.state != PM_STATE_SUSPEND_TO_IDLE) {
200 		LOG_DBG("Unsupported power state %u", info.state);
201 	} else {
202 		switch (info.substate_id) {
203 		case 0:	/* Sub-state 0: Deep sleep with instant wake-up */
204 			/* Restore interrupts */
205 			__enable_irq();
206 			break;
207 		case 1:	/* Sub-state 1: Deep sleep with standard wake-up */
208 			/* Restore interrupts */
209 			__enable_irq();
210 			break;
211 		default:
212 			LOG_DBG("Unsupported power substate-id %u",
213 				info.substate_id);
214 			break;
215 		}
216 	}
217 
218 	if (IS_ENABLED(CONFIG_SOC_POWER_MANAGEMENT_TRACE)) {
219 		LOG_DBG("sleep: %d, deep sleep: %d", cnt_sleep0, cnt_sleep1);
220 		LOG_INF("total ticks in sleep: %lld",
221 			npcx_clock_get_sleep_ticks());
222 	}
223 }
224