dvfs.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /*
  2. * Copyright (c) 2019 Actions Semiconductor Co., Ltd
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /**
  7. * @file dynamic voltage and frequency scaling interface
  8. */
  9. #include <kernel.h>
  10. #include <init.h>
  11. #include <device.h>
  12. #include <soc.h>
  13. #include <dvfs.h>
  14. #include <logging/log.h>
  15. LOG_MODULE_REGISTER(dvfs0, CONFIG_LOG_DEFAULT_LEVEL);
  16. #define CONFIG_DVFS_FADE_STEP
  17. #ifdef CONFIG_ACTS_DVFS_DYNAMIC_LEVEL
  18. struct dvfs_manager {
  19. struct k_sem lock;
  20. uint8_t cur_dvfs_idx;
  21. uint8_t default_dvfs_idx;
  22. uint8_t dvfs_level_cnt;
  23. uint8_t asrc_limit_clk_mhz;
  24. uint8_t spdif_limit_clk_mhz;
  25. struct dvfs_level *dvfs_level_tbl;
  26. };
  27. struct dvfs_level_max {
  28. uint16_t cpu_freq;
  29. uint16_t dsp_freq;
  30. uint16_t gpu_freq;
  31. uint16_t de_freq;
  32. uint16_t jpeg_freq;
  33. uint16_t vdd_volt;
  34. };
  35. static sys_dlist_t __dvfs_notifier_data dvfs_notify_list = SYS_DLIST_STATIC_INIT(&dvfs_notify_list);
  36. /* NOTE: DON'T modify max_soc_dvfs_table except actions ic designers */
  37. #define CPU_FREQ_MAX 128
  38. #define VDD_VOLT_MAX 1200
  39. /* vd12 and vdd should satisfy the need for voltage difference */
  40. #define DIFF_VD12_VDD_VOLT_MV 50
  41. static const struct dvfs_level_max max_soc_dvfs_table1[] = {
  42. /* cpu_freq, dsp_freq, gpu_freq, de_freq, jpeg_freq, vodd_volt */
  43. {16, 16, 16, 16, 16, 900},
  44. {70, 70, 70, 70, 70, 950},
  45. {94, 94, 94, 94, 140, 1000},
  46. {140, 140, 140, 140, 187, 1100},
  47. {187, 187, 187, 187, 280, 1200},
  48. };
  49. static const struct dvfs_level_max max_soc_dvfs_table0[] = {
  50. /* cpu_freq, dsp_freq, gpu_freq, de_freq, jpeg_freq, vodd_volt */
  51. {64, 64, 86, 86, 128, 1000},
  52. {86, 128, 128, 128, 171, 1100},
  53. {128, 171, 171, 171, 256, 1200},
  54. };
  55. static uint16_t dvfs_get_optimal_volt(uint16_t cpu_freq, uint16_t dsp_freq,
  56. uint16_t gpu_freq, uint16_t de_freq,
  57. uint16_t jpeg_freq,
  58. const struct dvfs_level_max *max_soc_dvfs_table,
  59. int level_cnt)
  60. {
  61. uint16_t volt;
  62. int i;
  63. volt = max_soc_dvfs_table[level_cnt - 1].vdd_volt;
  64. for (i = 0; i < level_cnt; i++) {
  65. if ((cpu_freq <= max_soc_dvfs_table[i].cpu_freq)
  66. && (dsp_freq <= max_soc_dvfs_table[i].dsp_freq)
  67. && (gpu_freq <= max_soc_dvfs_table[i].gpu_freq)
  68. && (de_freq <= max_soc_dvfs_table[i].de_freq)
  69. && (jpeg_freq <= max_soc_dvfs_table[i].jpeg_freq)) {
  70. volt = max_soc_dvfs_table[i].vdd_volt;
  71. break;
  72. }
  73. }
  74. return volt;
  75. }
  76. static struct dvfs_level default_soc_dvfs_table1[] = {
  77. /* level enable_cnt cpu_freq, dsp_freq, gpu_freq, de_freq, jpeg_freq, vodd_volt */
  78. {DVFS_LEVEL_S2, 0, 70, 70, 70, 70, 70, 0},
  79. {DVFS_LEVEL_NORMAL, 0, 94, 94, 94, 94, 140, 0},
  80. {DVFS_LEVEL_PERFORMANCE, 0, 94, 112, 94, 94, 140, 0},
  81. {DVFS_LEVEL_MID_PERFORMANCE, 0, 140, 112, 140, 140, 187, 0},
  82. {DVFS_LEVEL_HIGH_PERFORMANCE, 0, 187, 187, 187, 187, 280, 0},
  83. };
  84. static struct dvfs_level default_soc_dvfs_table0[] = {
  85. /* level enable_cnt cpu_freq, dsp_freq, gpu_freq, de_freq, jpeg_freq, vodd_volt */
  86. {DVFS_LEVEL_S2, 0, 64, 64, 86, 86, 128, 0},
  87. {DVFS_LEVEL_NORMAL, 0, 86, 128, 128, 128, 171, 0},
  88. {DVFS_LEVEL_PERFORMANCE, 0, 86, 128, 128, 128, 171, 0},
  89. {DVFS_LEVEL_MID_PERFORMANCE, 0, 96, 128, 128, 128, 171, 0},
  90. {DVFS_LEVEL_HIGH_PERFORMANCE, 0, 128, 171, 171, 171, 256, 0},
  91. };
  92. static struct dvfs_manager g_dvfs;
  93. #if 0
  94. static int level_id_to_vdd(int level_id)
  95. {
  96. int i;
  97. for (i = 0; i < g_dvfs.dvfs_level_cnt; i++)
  98. if (g_dvfs.dvfs_level_tbl[i].level_id == level_id) {
  99. return g_dvfs.dvfs_level_tbl[i].vdd_volt;
  100. }
  101. return -1;
  102. }
  103. #endif
  104. static int level_id_to_tbl_idx(int level_id)
  105. {
  106. int i;
  107. for (i = 0; i < g_dvfs.dvfs_level_cnt; i++) {
  108. if (g_dvfs.dvfs_level_tbl[i].level_id == level_id) {
  109. return i;
  110. }
  111. }
  112. return -1;
  113. }
  114. static int dvfs_get_max_idx(void)
  115. {
  116. int i;
  117. for (i = (g_dvfs.dvfs_level_cnt - 1); i >= 0; i--) {
  118. if (g_dvfs.dvfs_level_tbl[i].enable_cnt > 0) {
  119. return i;
  120. }
  121. }
  122. return -1;
  123. }
  124. static void dvfs_dump_tbl(void)
  125. {
  126. const struct dvfs_level *dvfs_level = &g_dvfs.dvfs_level_tbl[0];
  127. int i;
  128. printk("idx level_id dsp cpu gpu de jpeg vdd enable_cnt\n");
  129. for (i = 0; i < g_dvfs.dvfs_level_cnt; i++, dvfs_level++) {
  130. printk("%-6d%-11d%-6d%-6d%-6d%-6d%-6d%-6d%-6d\n", i,
  131. dvfs_level->level_id,
  132. dvfs_level->dsp_freq,
  133. dvfs_level->cpu_freq,
  134. dvfs_level->gpu_freq,
  135. dvfs_level->de_freq,
  136. dvfs_level->jpeg_freq,
  137. dvfs_level->vdd_volt,
  138. dvfs_level->enable_cnt);
  139. }
  140. }
  141. __dvfs_notifier_func static void dvfs_changed_notify(int state, uint8_t old_level_index, uint8_t new_level_index)
  142. {
  143. struct dvfs_notifier *obj, *next;
  144. struct dvfs_freqs dvfs_freqs_info = {0};
  145. dvfs_freqs_info.state = state;
  146. dvfs_freqs_info.old_level = old_level_index;
  147. dvfs_freqs_info.new_level = new_level_index;
  148. SYS_DLIST_FOR_EACH_CONTAINER_SAFE(&dvfs_notify_list, obj, next, node) {
  149. LOG_DBG("dvfs notify state:%d func:%p\n", state, obj->dvfs_notify_func_t);
  150. if (obj->dvfs_notify_func_t)
  151. obj->dvfs_notify_func_t(obj->user_data, &dvfs_freqs_info);
  152. }
  153. }
  154. static void dvfs_sync(void)
  155. {
  156. struct dvfs_level *dvfs_level, *old_dvfs_level;
  157. int old_idx, new_idx;
  158. uint32_t old_dsp_freq, old_volt, volt;
  159. uint8_t __old_idx, __new_idx, cur_idx;
  160. old_idx = g_dvfs.cur_dvfs_idx;
  161. /* get current max dvfs level */
  162. new_idx = dvfs_get_max_idx();
  163. if (new_idx == old_idx) {
  164. /* same level, no need sync */
  165. LOG_INF("max idx %d\n", new_idx);
  166. return;
  167. }
  168. /* if all dvfs levels are not enabled to use the default level */
  169. if (-1 == new_idx) {
  170. LOG_INF("dvfs use default level:%d", g_dvfs.default_dvfs_idx);
  171. new_idx = g_dvfs.default_dvfs_idx;
  172. }
  173. cur_idx = old_idx;
  174. while (cur_idx != new_idx) {
  175. __old_idx = cur_idx;
  176. #ifdef CONFIG_DVFS_FADE_STEP
  177. if (cur_idx > new_idx)
  178. cur_idx--;
  179. else
  180. cur_idx++;
  181. #else
  182. cur_idx = new_idx;
  183. #endif
  184. __new_idx = cur_idx;
  185. dvfs_level = &g_dvfs.dvfs_level_tbl[__new_idx];
  186. old_dvfs_level = &g_dvfs.dvfs_level_tbl[__old_idx];
  187. old_volt = soc_pmu_get_vdd_voltage();
  188. old_dsp_freq = soc_freq_get_dsp_freq();
  189. LOG_INF("level_id [%d] -> [%d]", old_dvfs_level->level_id,
  190. dvfs_level->level_id);
  191. /* send notify before clock setting */
  192. dvfs_changed_notify(DVFS_EVENT_PRE_CHANGE, __old_idx, __new_idx);
  193. /* set vdd voltage before clock setting if new vdd is up */
  194. if (dvfs_level->vdd_volt > old_volt) {
  195. /*check dcdc or ldo mode, if ldo mode ,need add 100mv, dcdc mode add 50mv */
  196. if((sys_read32(VOUT_CTL0) & BIT(17))) {
  197. soc_pmu_set_vd12_voltage(dvfs_level->vdd_volt + DIFF_VD12_VDD_VOLT_MV);
  198. } else {
  199. soc_pmu_set_vd12_voltage(dvfs_level->vdd_volt + DIFF_VD12_VDD_VOLT_MV * 2);
  200. }
  201. volt = old_volt;
  202. while(volt < dvfs_level->vdd_volt) {
  203. volt += 50 ; // step 0.05v, for psram/
  204. soc_pmu_set_vdd_voltage(volt);
  205. }
  206. }
  207. printk("new dsp freq %d, cpu freq %d, gpu freq %d, de freq %d, jpeg freq %d, vdd volt %d\n",
  208. dvfs_level->dsp_freq, dvfs_level->cpu_freq,
  209. dvfs_level->gpu_freq, dvfs_level->de_freq,
  210. dvfs_level->jpeg_freq, dvfs_level->vdd_volt);
  211. /* adjust core/dsp/cpu clock */
  212. soc_freq_set_cpu_clk(dvfs_level->dsp_freq, dvfs_level->cpu_freq);
  213. /* adjust gpu/de/jpeg clock.
  214. * freq=0 will be ignored for the case of not used condition,
  215. * such as lark not use jpeg, so jpeg_mhz can be set 0.
  216. */
  217. soc_freq_set_gpu_clk(dvfs_level->gpu_freq,
  218. dvfs_level->de_freq,
  219. dvfs_level->jpeg_freq);
  220. /* set vdd voltage after clock setting if new vdd is down */
  221. if (dvfs_level->vdd_volt < old_volt) {
  222. soc_pmu_set_vdd_voltage(dvfs_level->vdd_volt);
  223. /*check dcdc or ldo mode, if ldo mode ,need add 100mv, dcdc mode add 50mv */
  224. if((sys_read32(VOUT_CTL0) & BIT(17))) {
  225. soc_pmu_set_vd12_voltage(dvfs_level->vdd_volt + DIFF_VD12_VDD_VOLT_MV);
  226. } else {
  227. soc_pmu_set_vd12_voltage(dvfs_level->vdd_volt + DIFF_VD12_VDD_VOLT_MV * 2);
  228. }
  229. }
  230. /* send notify after clock setting */
  231. dvfs_changed_notify(DVFS_EVENT_POST_CHANGE, __old_idx, __new_idx);
  232. }
  233. g_dvfs.cur_dvfs_idx = new_idx;
  234. }
  235. static int dvfs_update_freq(int level_id, bool is_set, const char *user_info)
  236. {
  237. struct dvfs_level *dvfs_level;
  238. int tbl_idx;
  239. LOG_INF("level %d, is_set %d %s", level_id, is_set, user_info);
  240. tbl_idx = level_id_to_tbl_idx(level_id);
  241. if (tbl_idx < 0) {
  242. LOG_ERR("%s: invalid level id %d\n", __func__, level_id);
  243. return -EINVAL;
  244. }
  245. dvfs_level = &g_dvfs.dvfs_level_tbl[tbl_idx];
  246. k_sem_take(&g_dvfs.lock, K_FOREVER);
  247. if (is_set) {
  248. if(dvfs_level->enable_cnt < 255){
  249. dvfs_level->enable_cnt++;
  250. }else{
  251. LOG_WRN("max dvfs level count");
  252. }
  253. } else {
  254. if (dvfs_level->enable_cnt > 0) {
  255. dvfs_level->enable_cnt--;
  256. }else{
  257. LOG_WRN("min dvfs level count");
  258. }
  259. }
  260. dvfs_sync();
  261. k_sem_give(&g_dvfs.lock);
  262. return 0;
  263. }
  264. int dvfs_force_set_level(int level_id, const char *user_info)
  265. {
  266. return dvfs_update_freq(level_id, 1, user_info);
  267. }
  268. int dvfs_force_unset_level(int level_id, const char *user_info)
  269. {
  270. return dvfs_update_freq(level_id, 0, user_info);
  271. }
  272. static bool dvfs_lock_flag = false;
  273. int dvfs_lock(void)
  274. {
  275. dvfs_lock_flag = true;
  276. return 0;
  277. }
  278. int dvfs_unlock(void)
  279. {
  280. dvfs_lock_flag = false;
  281. return 0;
  282. }
  283. int dvfs_set_level(int level_id, const char *user_info)
  284. {
  285. if (!dvfs_lock_flag) {
  286. return dvfs_update_freq(level_id, 1, user_info);
  287. } else {
  288. printk("dvfs locked \n");
  289. return 0;
  290. }
  291. }
  292. int dvfs_unset_level(int level_id, const char *user_info)
  293. {
  294. if (!dvfs_lock_flag) {
  295. return dvfs_update_freq(level_id, 0, user_info);
  296. } else {
  297. printk("dvfs locked \n");
  298. return 0;
  299. }
  300. }
  301. int dvfs_get_current_level(void)
  302. {
  303. int idx;
  304. if (!g_dvfs.dvfs_level_tbl)
  305. return -1;
  306. idx = g_dvfs.cur_dvfs_idx;
  307. if (idx < 0) {
  308. idx = 0;
  309. }
  310. return g_dvfs.dvfs_level_tbl[idx].level_id;
  311. }
  312. int dvfs_set_freq_table(struct dvfs_level *dvfs_level_tbl, int level_cnt)
  313. {
  314. int i;
  315. //uint32_t vdd;
  316. if ((!dvfs_level_tbl) || (level_cnt <= 0))
  317. return -EINVAL;
  318. if (soc_dvfs_opt()) {
  319. for (i = 0; i < level_cnt; i++) {
  320. dvfs_level_tbl[i].vdd_volt =
  321. dvfs_get_optimal_volt(dvfs_level_tbl[i].cpu_freq,
  322. dvfs_level_tbl[i].dsp_freq,
  323. dvfs_level_tbl[i].gpu_freq,
  324. dvfs_level_tbl[i].de_freq,
  325. dvfs_level_tbl[i].jpeg_freq,
  326. max_soc_dvfs_table1,
  327. ARRAY_SIZE(max_soc_dvfs_table1));
  328. }
  329. }
  330. else {
  331. for (i = 0; i < level_cnt; i++) {
  332. dvfs_level_tbl[i].vdd_volt =
  333. dvfs_get_optimal_volt(dvfs_level_tbl[i].cpu_freq,
  334. dvfs_level_tbl[i].dsp_freq,
  335. dvfs_level_tbl[i].gpu_freq,
  336. dvfs_level_tbl[i].de_freq,
  337. dvfs_level_tbl[i].jpeg_freq,
  338. max_soc_dvfs_table0,
  339. ARRAY_SIZE(max_soc_dvfs_table0));
  340. }
  341. }
  342. g_dvfs.dvfs_level_cnt = level_cnt;
  343. g_dvfs.dvfs_level_tbl = dvfs_level_tbl;
  344. /* current dvfs id set to DVFS_LEVEL_HIGH_PERFORMANCE - 1 */
  345. /* make sure we can init DVFS_LEVEL_HIGH_PERFORMANCE first time */
  346. #if 0
  347. /* default level/vdd */
  348. vdd = soc_pmu_get_vdd_voltage();
  349. /* search for current vdd level */
  350. for (i = 0; i < g_dvfs.dvfs_level_cnt; i++) {
  351. if (g_dvfs.dvfs_level_tbl[i].vdd_volt >= vdd) {
  352. break;
  353. }
  354. }
  355. if (i != g_dvfs.dvfs_level_cnt)
  356. g_dvfs.cur_dvfs_idx = i;
  357. else
  358. g_dvfs.cur_dvfs_idx = 0;
  359. #endif
  360. g_dvfs.cur_dvfs_idx = level_id_to_tbl_idx(DVFS_LEVEL_MID_PERFORMANCE);
  361. g_dvfs.default_dvfs_idx = level_id_to_tbl_idx(DVFS_LEVEL_S2);
  362. printk("current dvfs level_id:%d default_dvfs_idx %d \n", g_dvfs.cur_dvfs_idx, g_dvfs.default_dvfs_idx);
  363. dvfs_dump_tbl();
  364. return 0;
  365. }
  366. struct dvfs_level *dvfs_get_info_by_level_id(int level_id)
  367. {
  368. return &g_dvfs.dvfs_level_tbl[level_id];
  369. }
  370. int dvfs_register_notifier(struct dvfs_notifier *notifier)
  371. {
  372. struct dvfs_notifier *obj;
  373. if (!notifier)
  374. return -EINVAL;
  375. SYS_DLIST_FOR_EACH_CONTAINER(&dvfs_notify_list, obj, node) {
  376. if (obj == notifier) {
  377. LOG_ERR("dvfs notifier:%p has already registered", notifier);
  378. return -EEXIST;
  379. }
  380. }
  381. sys_dlist_append(&dvfs_notify_list, &notifier->node);
  382. LOG_DBG("dvfs register notifier:%p func:%p\n",
  383. notifier, notifier->dvfs_notify_func_t);
  384. return 0;
  385. }
  386. int dvfs_unregister_notifier(struct dvfs_notifier *notifier)
  387. {
  388. if (!notifier)
  389. return -EINVAL;
  390. sys_dlist_remove(&notifier->node);
  391. return 0;
  392. }
  393. #endif /* CONFIG_ACTS_DVFS_DYNAMIC_LEVEL */
  394. static int dvfs_init(const struct device *arg)
  395. {
  396. ARG_UNUSED(arg);
  397. LOG_INF("default dsp freq:%dHz cpu freq:%dHz vdd:%dmV",
  398. soc_freq_get_dsp_freq(), soc_freq_get_cpu_freq(),
  399. soc_pmu_get_vdd_voltage());
  400. #ifdef CONFIG_ACTS_DVFS_DYNAMIC_LEVEL
  401. if (soc_dvfs_opt()) {
  402. dvfs_set_freq_table(default_soc_dvfs_table1,
  403. ARRAY_SIZE(default_soc_dvfs_table1));
  404. }
  405. else {
  406. dvfs_set_freq_table(default_soc_dvfs_table0,
  407. ARRAY_SIZE(default_soc_dvfs_table0));
  408. }
  409. k_sem_init(&g_dvfs.lock, 1, 1);
  410. dvfs_set_level(DVFS_LEVEL_HIGH_PERFORMANCE, "init");
  411. #endif
  412. return 0;
  413. }
  414. SYS_INIT(dvfs_init, PRE_KERNEL_1, 20);