soc_pm.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. * Copyright (c) 2018 Actions Semiconductor Co., Ltd
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /**
  7. * @file system reboot interface for Actions SoC
  8. */
  9. #include <device.h>
  10. #include <init.h>
  11. #include <soc.h>
  12. #include <pm/pm.h>
  13. #include <drivers/rtc.h>
  14. #include <board_cfg.h>
  15. #include <drivers/nvram_config.h>
  16. #include <drivers/flash.h>
  17. #define REBOOT_REASON_MAGIC 0x4252 /* 'RB' */
  18. int sys_pm_get_wakeup_source(union sys_pm_wakeup_src *src)
  19. {
  20. uint32_t wk_pd;
  21. if (!src)
  22. return -EINVAL;
  23. src->data = 0;
  24. wk_pd = soc_pmu_get_wakeup_source();
  25. if (wk_pd & BIT(0))
  26. src->t.long_onoff = 1;
  27. if (wk_pd & BIT(1))
  28. src->t.short_onoff = 1;
  29. if (wk_pd & BIT(13))
  30. src->t.bat = 1;
  31. if (wk_pd & BIT(5))
  32. src->t.wio = 1;
  33. if (wk_pd & BIT(12))
  34. src->t.remote = 1;
  35. if (wk_pd & BIT(4))
  36. src->t.alarm = 1;
  37. if (wk_pd & BIT(11))
  38. src->t.batlv = 1;
  39. if (wk_pd & BIT(10))
  40. src->t.dc5vlv = 1;
  41. if (wk_pd & BIT(2))
  42. src->t.dc5vin = 1;
  43. if (soc_boot_get_watchdog_is_reboot() == 1)
  44. src->t.watchdog = 1;
  45. return 0;
  46. }
  47. void sys_pm_set_wakeup_src(void)
  48. {
  49. uint32_t key, val;
  50. key = irq_lock();
  51. val = sys_read32(WKEN_CTL_SVCC) & (~0x1fff);
  52. val = WAKE_CTL_LONG_WKEN | WAKE_CTL_ALARM8HZ_WKEN | WAKE_CTL_WIO0LV_DETEN;
  53. if(!soc_pmu_get_dc5v_status()) {
  54. val |= WAKE_CTL_DC5VIN_WKEN;
  55. }
  56. sys_write32(val, WKEN_CTL_SVCC);
  57. k_busy_wait(500);
  58. irq_unlock(key);
  59. }
  60. /*
  61. ** system power off to cal rtc
  62. */
  63. static void sys_pm_poweroff_rtc(void)
  64. {
  65. unsigned int key;
  66. #ifdef CONFIG_ACTIONS_PRINTK_DMA
  67. printk_dma_switch(0);
  68. #endif
  69. sys_write32(sys_read32(WAKE_PD_SVCC), WAKE_PD_SVCC);
  70. printk("system power down!WKEN_CTL=0x%x\n", sys_read32(WKEN_CTL_SVCC));
  71. key = irq_lock();
  72. #ifdef CONFIG_PM_DEVICE
  73. printk("dev power off\n");
  74. pm_power_off_devices();
  75. printk("dev power end\n");
  76. #endif
  77. while(1) {
  78. sys_write32(0, POWER_CTL_SVCC);
  79. /* wait 10ms */
  80. k_busy_wait(10000);
  81. printk("poweroff fail, need reboot!\n");
  82. }
  83. }
  84. /*@brief 8hzchcle cal to ms by rc32k
  85. rc32k_sum = rc32k_old + rc32k_new
  86. */
  87. static uint32_t sys_pmu_8hzcycle_to_ms(uint32_t cycle, uint32_t rc32k_sum)
  88. {
  89. uint64_t cal = cycle;
  90. uint32_t ms;
  91. ms = cal*(32768*125*2)/rc32k_sum; // cal interval ms
  92. return ms;
  93. }
  94. static void sys_pm_rtc_backup_check(void)
  95. {
  96. int ret;
  97. union sys_pm_wakeup_src wk_src;
  98. struct sys_pm_backup_time pm_bak_time = {0};
  99. uint32_t rc32k_freq_sum, new_rc32k_freq;
  100. uint32_t counter8hz_cycles, interval_cycles, cur_time_sec, ms, sec;
  101. soc_pstore_set(SOC_PSTORE_TAG_RTC_RC32K_CAL, 1);
  102. sys_pm_get_wakeup_source(&wk_src);
  103. if(!wk_src.t.alarm)
  104. return;
  105. ret = nvram_config_get(CONFIG_PM_BACKUP_TIME_NVRAM_ITEM_NAME,
  106. &pm_bak_time, sizeof(struct sys_pm_backup_time));
  107. if (ret != sizeof(struct sys_pm_backup_time)) {
  108. printk("boot:failed to get pm backup time to nvram =%d\n", ret);
  109. return;
  110. }
  111. if(pm_bak_time.is_user_cur_use){
  112. printk("the user's alarm\n");// go to system handle
  113. pm_bak_time.is_user_alarm_on = 0;
  114. ret = nvram_config_set(CONFIG_PM_BACKUP_TIME_NVRAM_ITEM_NAME,
  115. &pm_bak_time, sizeof(struct sys_pm_backup_time));
  116. if (ret) {
  117. printk("failed to save pm backup time to nvram");
  118. }
  119. return;
  120. }
  121. if(pm_bak_time.is_use_alarm_cal && pm_bak_time.is_backup_time_valid){
  122. uint32_t alram_ms = 1000*60*60; // 1h wakeup
  123. new_rc32k_freq = acts_clock_rc32k_set_cal_cyc(200);
  124. printk("rc32k_freq=%d,old=%d\n", new_rc32k_freq, pm_bak_time.rc32k_freq);
  125. ret = soc_pmu_get_counter8hz_cycles(false);
  126. if(ret < 0 )
  127. return;
  128. counter8hz_cycles = ret;
  129. printk("current 8hz: %d\n", counter8hz_cycles);
  130. /* counter8hz overflow */
  131. if (counter8hz_cycles < pm_bak_time.counter8hz_cycles) {
  132. interval_cycles = PMU_COUTNER8HZ_MAX - pm_bak_time.counter8hz_cycles + counter8hz_cycles;
  133. } else {
  134. interval_cycles = counter8hz_cycles - pm_bak_time.counter8hz_cycles;
  135. }
  136. cur_time_sec = pm_bak_time.rtc_time_sec;
  137. rc32k_freq_sum = (pm_bak_time.rc32k_freq + new_rc32k_freq); // old + new
  138. ms = sys_pmu_8hzcycle_to_ms(interval_cycles, rc32k_freq_sum) + pm_bak_time.rtc_time_msec;
  139. cur_time_sec += ms / 1000;
  140. ms = ms % 1000 ;
  141. sec = cur_time_sec - pm_bak_time.rtc_time_sec;
  142. pm_bak_time.rtc_time_sec = cur_time_sec;
  143. pm_bak_time.rtc_time_msec = ms;
  144. pm_bak_time.counter8hz_cycles = counter8hz_cycles;
  145. pm_bak_time.rc32k_freq = new_rc32k_freq;
  146. printk("time: %ds, %dms, interval=%d\n", cur_time_sec, ms, sec);
  147. if(pm_bak_time.is_user_alarm_on){// user alarm on ,check if next hour is user alarm
  148. if(pm_bak_time.user_alarm_cycles > counter8hz_cycles){
  149. interval_cycles = pm_bak_time.user_alarm_cycles - counter8hz_cycles;
  150. }else{
  151. interval_cycles = PMU_COUTNER8HZ_MAX - counter8hz_cycles + pm_bak_time.user_alarm_cycles;
  152. }
  153. ms = (uint64_t)interval_cycles*32768*125 /new_rc32k_freq; // cal real ms
  154. printk("b user set alarm after %d ms\n", ms);
  155. if(ms < alram_ms*2) { // It is multiplied by 2 because the user's alarm may be lost due to calculation error
  156. alram_ms = ms; // use user alarm
  157. pm_bak_time.is_user_cur_use = 1;
  158. printk("b set user alarm\n");
  159. }
  160. }
  161. ret = nvram_config_set(CONFIG_PM_BACKUP_TIME_NVRAM_ITEM_NAME,
  162. &pm_bak_time, sizeof(struct sys_pm_backup_time));
  163. if (ret) {
  164. printk("failed to save pm backup time to nvram");
  165. return ;
  166. }
  167. soc_pmu_alarm8hz_enable(alram_ms);
  168. printk("bootloader pwoer off set next alarm=%d ms\n", alram_ms);
  169. sys_pm_poweroff_rtc();
  170. }
  171. }
  172. static int sys_pm_rtc_backup_init(const struct device *arg)
  173. {
  174. sys_pm_rtc_backup_check();
  175. return 0;
  176. }
  177. SYS_INIT(sys_pm_rtc_backup_init, APPLICATION, 99);
  178. /*
  179. ** system power off
  180. */
  181. void sys_pm_poweroff(void)
  182. {
  183. unsigned int key;
  184. /* wait 10ms, avoid trigger onoff wakeup pending */
  185. k_busy_wait(10000);
  186. #ifdef CONFIG_ACTIONS_PRINTK_DMA
  187. printk_dma_switch(0);
  188. #endif
  189. sys_pm_set_wakeup_src();
  190. printk("system power down!WKEN_CTL=0x%x\n", sys_read32(WKEN_CTL_SVCC));
  191. key = irq_lock();
  192. #ifdef CONFIG_PM_DEVICE
  193. printk("dev power off\n");
  194. pm_power_off_devices();
  195. printk("dev power end\n");
  196. #endif
  197. #ifdef CONFIG_SPINAND_ACTS
  198. flash_flush(device_get_binding("spinand"), 0);
  199. #endif
  200. while(1) {
  201. sys_write32(0, POWER_CTL_SVCC);
  202. /* wait 10ms */
  203. k_busy_wait(10000);
  204. printk("poweroff fail, need reboot!\n");
  205. sys_pm_reboot(0);
  206. }
  207. /* never return... */
  208. }
  209. void sys_pm_reboot(int type)
  210. {
  211. unsigned int key;
  212. #ifdef CONFIG_ACTIONS_PRINTK_DMA
  213. printk_dma_switch(0);
  214. #endif
  215. if(type == REBOOT_TYPE_GOTO_SWJTAG){
  216. printk("set jtag flag\n");
  217. type = REBOOT_TYPE_NORMAL;
  218. sys_set_bit(RTC_REMAIN2, 0); //bit 0 adfu flag
  219. }
  220. printk("system reboot, type 0x%x!\n", type);
  221. key = irq_lock();
  222. #ifdef CONFIG_SPINAND_ACTS
  223. flash_flush(device_get_binding("spinand"), 0);
  224. #endif
  225. /* store reboot reason in RTC_REMAIN0 for bootloader */
  226. sys_write32((REBOOT_REASON_MAGIC << 16) | (type & 0xffff), RTC_REMAIN3);
  227. k_busy_wait(500);
  228. sys_write32(0x5f, WD_CTL);
  229. while (1) {
  230. ;
  231. }
  232. /* never return... */
  233. }
  234. int sys_pm_get_reboot_reason(u16_t *reboot_type, u8_t *reason)
  235. {
  236. uint32_t reg_val;
  237. reg_val = soc_boot_get_reboot_reason();
  238. *reboot_type = reg_val & 0xff00;
  239. *reason = reg_val & 0xff;
  240. return 0;
  241. }
  242. static void ctk_close(void)
  243. {
  244. int i;
  245. for(i = 0; i < 20; i++) // tpkey poweroff
  246. {
  247. sys_write32(0x40000009, CTK_CTL);
  248. sys_write32(0x4000000d, CTK_CTL);
  249. }
  250. }
  251. __ramfunc void soc_udelay(uint32_t us)
  252. {
  253. uint32_t cycles_per_1us, wait_cycles;
  254. volatile uint32_t i;
  255. uint8_t cpuclk_src = sys_read32(CMU_SYSCLK) & 0x7;
  256. if (cpuclk_src == 0)
  257. cycles_per_1us = 4;
  258. else if (cpuclk_src == 1)
  259. cycles_per_1us = 25;
  260. else if (cpuclk_src == 3)
  261. cycles_per_1us = 56; /* %15 deviation */
  262. else
  263. cycles_per_1us = 74;
  264. wait_cycles = cycles_per_1us * us / 10;
  265. for (i = 0; i < wait_cycles; i++) { /* totally 13 instruction cycles */
  266. ;
  267. }
  268. }
  269. static int soc_pm_init(const struct device *arg)
  270. {
  271. printk("WAKE_PD_SVCC = 0x%x\n", sys_read32(WAKE_PD_SVCC));
  272. sys_write32(0x3, CMU_S1CLKCTL); // hosc+rc4m
  273. sys_write32(0x3, CMU_S1BTCLKCTL); // hosc+rc4m
  274. sys_write32(0x1, CMU_S2SCLKCTL); // RC4M enable
  275. sys_write32(0x8, CMU_S3CLKCTL); // S3 colse hosc and RC4M, enable RAM4 CLK SPIMT ICMT CLK ENABLE
  276. sys_write32(0x0, CMU_PMUWKUPCLKCTL); //select wk clk RC32K, if sel RC4M/4 ,must enable RC4M IN sleep
  277. sys_write32(0x1, CMU_GPIOCLKCTL); //select gpio clk RC4M
  278. sys_write32(0x06202053, VOUT_CTL1_S3);//VDD=0.7, vdd1.2=0.7
  279. sys_write32(0x5958, RC4M_CTL);
  280. ctk_close();
  281. return 0;
  282. }
  283. SYS_INIT(soc_pm_init, PRE_KERNEL_1, 20);