1 /*
2 * Copyright (C) 2018 Shanghai Eastsoft Microelectronics Co., Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * Change Logs:
19 * Date Author Notes
20 * 2020-12-15 liuhy the first version
21 */
22
23 #include "drv_pm.h"
24
25 #ifdef RT_USING_PM
26
27
save_register(void * p_head,uint32_t size,void * p_save)28 void save_register(void *p_head,uint32_t size,void *p_save)
29 {
30 memcpy(p_save,p_head,size);
31 }
32
load_register(void * p_head,uint32_t size,void * p_load)33 void load_register(void *p_head,uint32_t size,void *p_load)
34 {
35 memcpy(p_head,p_load,size);
36
37 #ifdef ES_PMU_SAVE_LOAD_UART
38
39 if((p_head == UART0) || (p_head == UART1) || (p_head == UART2) ||
40 (p_head == UART3) || (p_head == UART4) || (p_head == UART5) )
41 {
42 ((UART_TypeDef*)p_head)->IER = ((UART_TypeDef*)p_load)->IVS;
43 }
44 #endif
45
46 }
47
uart_console_reconfig(void)48 static void uart_console_reconfig(void)
49 {
50 struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
51
52 rt_device_control(rt_console_get_device(), RT_DEVICE_CTRL_CONFIG, &config);
53 }
54
55 /**
56 * This function will put ES32F369x into sleep mode.
57 *
58 * @param pm pointer to power manage structure
59 */
60
61
62 /* 注意:进入睡眠前,如果有中断挂起(SYSTICK、PENDSV、UART、EXTI等),睡眠将被瞬间唤醒。*/
sleep(struct rt_pm * pm,uint8_t mode)63 static void sleep(struct rt_pm *pm, uint8_t mode)
64 {
65
66 switch (mode)
67 {
68 case PM_SLEEP_MODE_NONE:
69 break;
70
71 case PM_SLEEP_MODE_IDLE:
72 break;
73
74 case PM_SLEEP_MODE_LIGHT:
75 /* Enter SLEEP Mode, Main regulator is ON */
76 ald_pmu_stop1_enter();
77 break;
78
79 case PM_SLEEP_MODE_DEEP:
80 /* Enter STOP 2 mode */
81 ald_pmu_stop2_enter();
82 break;
83
84 case PM_SLEEP_MODE_STANDBY:
85 /* Enter STANDBY mode */
86 ald_pmu_stop2_enter();
87 break;
88
89 case PM_SLEEP_MODE_SHUTDOWN:
90 /* Enter SHUTDOWNN mode */
91 ald_pmu_stop2_enter();
92 break;
93
94 default:
95 RT_ASSERT(0);
96 break;
97 }
98
99 }
100
101 static uint8_t run_speed[PM_RUN_MODE_MAX][2] =
102 {
103 {48, 0},
104 {48, 1},
105 {24, 2},
106 {2, 3},
107 };
108
run(struct rt_pm * pm,uint8_t mode)109 static void run(struct rt_pm *pm, uint8_t mode)
110 {
111 static uint8_t last_mode;
112 static char *run_str[] = PM_RUN_MODE_NAMES;
113 extern uint32_t __system_clock;
114
115 if (mode == last_mode)
116 return;
117 last_mode = mode;
118
119 ald_cmu_clock_config_default();
120 __system_clock = 24000000;
121 switch (mode)
122 {
123 case PM_RUN_MODE_HIGH_SPEED:
124 case PM_RUN_MODE_NORMAL_SPEED:
125 /* hosc 12MHz, from hosc/3 pll to 48MHz */
126 ald_cmu_pll1_config(CMU_PLL1_INPUT_HRC_6, CMU_PLL1_OUTPUT_48M);
127 /* MCLK 48MHz */
128 ald_cmu_clock_config(CMU_CLOCK_PLL1, 48000000);
129 break;
130 case PM_RUN_MODE_MEDIUM_SPEED:
131 break;
132 case PM_RUN_MODE_LOW_SPEED:
133 ald_cmu_clock_config(CMU_CLOCK_HRC, 2000000);
134 break;
135 default:
136 break;
137 }
138
139 /* 4. 更新外设时钟 */
140 uart_console_reconfig();
141 /* Re-Configure the Systick time */
142 SysTick_Config(ald_cmu_get_sys_clock() / RT_TICK_PER_SECOND);
143
144 rt_kprintf("switch to %s mode, frequency = %d MHz\n", run_str[mode], run_speed[mode][0]);
145 }
146
147 /**
148 * This function caculate the PM tick from OS tick
149 *
150 * @param tick OS tick
151 *
152 * @return the PM tick
153 */
es32f3_pm_tick_from_os_tick(rt_tick_t tick)154 static rt_tick_t es32f3_pm_tick_from_os_tick(rt_tick_t tick)
155 {
156 rt_uint32_t freq = 1;
157
158 return (freq * tick / RT_TICK_PER_SECOND);
159 }
160
161 /**
162 * This function caculate the OS tick from PM tick
163 *
164 * @param tick PM tick
165 *
166 * @return the OS tick
167 */
es32f3_os_tick_from_pm_tick(rt_uint32_t tick)168 static rt_tick_t es32f3_os_tick_from_pm_tick(rt_uint32_t tick)
169 {
170 static rt_uint32_t os_tick_remain = 0;
171 rt_uint32_t ret, freq;
172
173 freq = 1;
174 ret = (tick * RT_TICK_PER_SECOND + os_tick_remain) / freq;
175
176 os_tick_remain += (tick * RT_TICK_PER_SECOND);
177 os_tick_remain %= freq;
178
179 return ret;
180 }
181
182 /**
183 * This function start the timer of pm
184 *
185 * @param pm Pointer to power manage structure
186 * @param timeout How many OS Ticks that MCU can sleep
187 */
pm_timer_start(struct rt_pm * pm,rt_uint32_t timeout)188 static void pm_timer_start(struct rt_pm *pm, rt_uint32_t timeout)
189 {
190 RT_ASSERT(pm != RT_NULL);
191 RT_ASSERT(timeout > 0);
192
193 if (timeout != RT_TICK_MAX)
194 {
195 /* Convert OS Tick to pmtimer timeout value */
196 timeout = es32f3_pm_tick_from_os_tick(timeout);
197 /* MAX 0xFFFF */
198 if (timeout > 0xFFFF)
199 {
200 timeout = 0xFFFF;
201 }
202 }
203 }
204
205 /**
206 * This function stop the timer of pm
207 *
208 * @param pm Pointer to power manage structure
209 */
pm_timer_stop(struct rt_pm * pm)210 static void pm_timer_stop(struct rt_pm *pm)
211 {
212 RT_ASSERT(pm != RT_NULL);
213 }
214
215 /**
216 * This function calculate how many OS Ticks that MCU have suspended
217 *
218 * @param pm Pointer to power manage structure
219 *
220 * @return OS Ticks
221 */
pm_timer_get_tick(struct rt_pm * pm)222 static rt_tick_t pm_timer_get_tick(struct rt_pm *pm)
223 {
224 rt_uint32_t timer_tick;
225
226 RT_ASSERT(pm != RT_NULL);
227
228 timer_tick = 1;
229
230 return es32f3_os_tick_from_pm_tick(timer_tick);
231 }
232
233 /**
234 * This function initialize the power manager
235 */
drv_pm_hw_init(void)236 int drv_pm_hw_init(void)
237 {
238 static const struct rt_pm_ops _ops =
239 {
240 sleep,
241 run,
242 pm_timer_start,
243 pm_timer_stop,
244 pm_timer_get_tick
245 };
246
247 rt_uint8_t timer_mask = 0;
248
249 /* initialize timer mask */
250 timer_mask = 1UL << PM_SLEEP_MODE_DEEP;
251
252 /* initialize system pm module */
253 rt_system_pm_init(&_ops, timer_mask, RT_NULL);
254
255 return 0;
256 }
257 INIT_BOARD_EXPORT(drv_pm_hw_init);
258
259 #endif
260