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