mmdvfs_mgr.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. /*
  2. * Copyright (C) 2015 MediaTek Inc.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. */
  13. #if ((defined(SMI_D1) || defined(SMI_D2) || defined(SMI_D3)) && !IS_ENABLED(CONFIG_FPGA_EARLY_PORTING))
  14. #define MMDVFS_ENABLE 1
  15. #endif
  16. #include <linux/uaccess.h>
  17. #include <aee.h>
  18. #include <mt_smi.h>
  19. #include <linux/timer.h>
  20. #include <linux/jiffies.h>
  21. #include <linux/workqueue.h>
  22. #include <linux/delay.h>
  23. #include <mach/mt_freqhopping.h>
  24. #include <mach/mt_clkmgr.h>
  25. #include <mt_vcore_dvfs.h>
  26. #include <mt_freqhopping_drv.h>
  27. #include "mmdvfs_mgr.h"
  28. #undef pr_fmt
  29. #define pr_fmt(fmt) "[" MMDVFS_LOG_TAG "]" fmt
  30. #define MMDVFS_ENABLE_FLIPER_CONTROL 0
  31. /* #define MMDVFS_USE_APMCU_CLK_MUX_SWITCH */
  32. #if MMDVFS_ENABLE_FLIPER_CONTROL
  33. #include <mach/fliper.h>
  34. #endif
  35. /* mmdvfs MM sizes */
  36. #define MMDVFS_PIXEL_NUM_720P (1280 * 720)
  37. #define MMDVFS_PIXEL_NUM_2160P (3840 * 2160)
  38. #define MMDVFS_PIXEL_NUM_1080P (2100 * 1300)
  39. #define MMDVFS_PIXEL_NUM_2M (2100 * 1300)
  40. /* 13M sensor */
  41. #define MMDVFS_PIXEL_NUM_SENSOR_FULL (13000000)
  42. #define MMDVFS_PIXEL_NUM_SENSOR_6M (5800000)
  43. #define MMDVFS_PIXEL_NUM_SENSOR_8M (7800000)
  44. /* mmdvfs display sizes */
  45. #define MMDVFS_DISPLAY_SIZE_HD (1280 * 832)
  46. #define MMDVFS_DISPLAY_SIZE_FHD (1920 * 1216)
  47. /* + 1 for MMDVFS_CAM_MON_SCEN */
  48. static mmdvfs_voltage_enum g_mmdvfs_scenario_voltage[MMDVFS_SCEN_COUNT] = {
  49. MMDVFS_VOLTAGE_DEFAULT};
  50. static mmdvfs_voltage_enum g_mmdvfs_current_step;
  51. static unsigned int g_mmdvfs_concurrency;
  52. static MTK_SMI_BWC_MM_INFO *g_mmdvfs_info;
  53. static int g_mmdvfs_profile_id = MMDVFS_PROFILE_UNKNOWN;
  54. static MTK_MMDVFS_CMD g_mmdvfs_cmd;
  55. struct mmdvfs_context_struct {
  56. spinlock_t scen_lock;
  57. int is_mhl_enable;
  58. int is_mjc_enable;
  59. };
  60. /* mmdvfs_query() return value, remember to sync with user space */
  61. enum mmdvfs_step_enum {
  62. MMDVFS_STEP_LOW = 0, MMDVFS_STEP_HIGH,
  63. MMDVFS_STEP_LOW2LOW, /* LOW */
  64. MMDVFS_STEP_HIGH2LOW, /* LOW */
  65. MMDVFS_STEP_LOW2HIGH, /* HIGH */
  66. MMDVFS_STEP_HIGH2HIGH,
  67. /* HIGH */
  68. };
  69. /* lcd size */
  70. enum mmdvfs_lcd_size_enum {
  71. MMDVFS_LCD_SIZE_HD, MMDVFS_LCD_SIZE_FHD, MMDVFS_LCD_SIZE_WQHD, MMDVFS_LCD_SIZE_END_OF_ENUM
  72. };
  73. static struct mmdvfs_context_struct g_mmdvfs_mgr_cntx;
  74. static struct mmdvfs_context_struct * const g_mmdvfs_mgr = &g_mmdvfs_mgr_cntx;
  75. static enum mmdvfs_lcd_size_enum mmdvfs_get_lcd_resolution(void)
  76. {
  77. if (DISP_GetScreenWidth() * DISP_GetScreenHeight()
  78. <= MMDVFS_DISPLAY_SIZE_HD)
  79. return MMDVFS_LCD_SIZE_HD;
  80. return MMDVFS_LCD_SIZE_FHD;
  81. }
  82. static int vdec_ctrl_func_checked(vdec_ctrl_cb func, char *msg);
  83. static int notify_cb_func_checked(clk_switch_cb func, int ori_mmsys_clk_mode, int update_mmsys_clk_mode, char *msg);
  84. static int mmdfvs_adjust_mmsys_clk_by_hopping(int clk_mode);
  85. static int default_clk_switch_cb(int ori_mmsys_clk_mode, int update_mmsys_clk_mode);
  86. static int current_mmsys_clk = MMSYS_CLK_LOW;
  87. static mmdvfs_voltage_enum mmdvfs_get_default_step(void)
  88. {
  89. mmdvfs_voltage_enum result = MMDVFS_VOLTAGE_LOW;
  90. if (g_mmdvfs_profile_id == MMDVFS_PROFILE_D3)
  91. result = MMDVFS_VOLTAGE_LOW;
  92. else if (g_mmdvfs_profile_id == MMDVFS_PROFILE_D1_PLUS)
  93. result = MMDVFS_VOLTAGE_LOW;
  94. else
  95. if (mmdvfs_get_lcd_resolution() == MMDVFS_LCD_SIZE_HD)
  96. result = MMDVFS_VOLTAGE_LOW;
  97. else
  98. /* D1 FHD always HPM. do not have to trigger vcore dvfs. */
  99. result = MMDVFS_VOLTAGE_HIGH;
  100. return result;
  101. }
  102. static mmdvfs_voltage_enum mmdvfs_get_current_step(void)
  103. {
  104. return g_mmdvfs_current_step;
  105. }
  106. static mmdvfs_voltage_enum mmdvfs_query(MTK_SMI_BWC_SCEN scenario,
  107. MTK_MMDVFS_CMD *cmd)
  108. {
  109. mmdvfs_voltage_enum step = mmdvfs_get_default_step();
  110. unsigned int venc_size;
  111. MTK_MMDVFS_CMD cmd_default;
  112. venc_size = g_mmdvfs_info->video_record_size[0]
  113. * g_mmdvfs_info->video_record_size[1];
  114. /* use default info */
  115. if (cmd == NULL) {
  116. memset(&cmd_default, 0, sizeof(MTK_MMDVFS_CMD));
  117. cmd_default.camera_mode = MMDVFS_CAMERA_MODE_FLAG_DEFAULT;
  118. cmd = &cmd_default;
  119. }
  120. /* collect the final information */
  121. if (cmd->sensor_size == 0)
  122. cmd->sensor_size = g_mmdvfs_cmd.sensor_size;
  123. if (cmd->sensor_fps == 0)
  124. cmd->sensor_fps = g_mmdvfs_cmd.sensor_fps;
  125. if (cmd->camera_mode == MMDVFS_CAMERA_MODE_FLAG_DEFAULT)
  126. cmd->camera_mode = g_mmdvfs_cmd.camera_mode;
  127. /* HIGH level scenarios */
  128. switch (scenario) {
  129. #if defined(SMI_D2) /* D2 ISP >= 6M HIGH */
  130. case SMI_BWC_SCEN_VR_SLOW:
  131. case SMI_BWC_SCEN_VR:
  132. if (cmd->sensor_size >= MMDVFS_PIXEL_NUM_SENSOR_6M)
  133. step = MMDVFS_VOLTAGE_HIGH;
  134. break;
  135. #endif
  136. case SMI_BWC_SCEN_ICFP:
  137. step = MMDVFS_VOLTAGE_HIGH;
  138. break;
  139. /* force HPM for engineering mode */
  140. case SMI_BWC_SCEN_FORCE_MMDVFS:
  141. step = MMDVFS_VOLTAGE_HIGH;
  142. break;
  143. default:
  144. break;
  145. }
  146. return step;
  147. }
  148. static void mmdvfs_update_cmd(MTK_MMDVFS_CMD *cmd)
  149. {
  150. if (cmd == NULL)
  151. return;
  152. if (cmd->sensor_size)
  153. g_mmdvfs_cmd.sensor_size = cmd->sensor_size;
  154. if (cmd->sensor_fps)
  155. g_mmdvfs_cmd.sensor_fps = cmd->sensor_fps;
  156. MMDVFSMSG("update cm %d %d\n", cmd->camera_mode, cmd->sensor_size);
  157. g_mmdvfs_cmd.camera_mode = cmd->camera_mode;
  158. }
  159. /* delay 4 seconds to go LPM to workaround camera ZSD + PIP issue */
  160. #if !defined(SMI_D3)
  161. static void mmdvfs_cam_work_handler(struct work_struct *work)
  162. {
  163. MMDVFSMSG("CAM handler %d\n", jiffies_to_msecs(jiffies));
  164. mmdvfs_set_step(MMDVFS_CAM_MON_SCEN, mmdvfs_get_default_step());
  165. }
  166. static DECLARE_DELAYED_WORK(g_mmdvfs_cam_work, mmdvfs_cam_work_handler);
  167. static void mmdvfs_stop_cam_monitor(void)
  168. {
  169. cancel_delayed_work_sync(&g_mmdvfs_cam_work);
  170. }
  171. #define MMDVFS_CAM_MON_DELAY (4 * HZ)
  172. static void mmdvfs_start_cam_monitor(void)
  173. {
  174. mmdvfs_stop_cam_monitor();
  175. MMDVFSMSG("CAM start %d\n", jiffies_to_msecs(jiffies));
  176. mmdvfs_set_step(MMDVFS_CAM_MON_SCEN, MMDVFS_VOLTAGE_HIGH);
  177. /* 4 seconds for PIP switch preview aspect delays... */
  178. schedule_delayed_work(&g_mmdvfs_cam_work, MMDVFS_CAM_MON_DELAY);
  179. }
  180. #endif /* !defined(SMI_D3) */
  181. int mmdvfs_set_step(MTK_SMI_BWC_SCEN scenario, mmdvfs_voltage_enum step)
  182. {
  183. int i, scen_index;
  184. unsigned int concurrency = 0;
  185. mmdvfs_voltage_enum final_step = mmdvfs_get_default_step();
  186. #if !MMDVFS_ENABLE
  187. return 0;
  188. #endif
  189. if (!is_vcorefs_can_work())
  190. return 0;
  191. /* D1 FHD always HPM. do not have to trigger vcore dvfs. */
  192. if (g_mmdvfs_profile_id == MMDVFS_PROFILE_D1
  193. && mmdvfs_get_lcd_resolution() == MMDVFS_LCD_SIZE_FHD)
  194. return 0;
  195. /* D1 plus FHD only allowed DISP as the client */
  196. if (g_mmdvfs_profile_id == MMDVFS_PROFILE_D1_PLUS)
  197. if (mmdvfs_get_lcd_resolution() == MMDVFS_LCD_SIZE_FHD
  198. && scenario != (MTK_SMI_BWC_SCEN) MMDVFS_SCEN_DISP)
  199. return 0;
  200. if ((scenario >= (MTK_SMI_BWC_SCEN) MMDVFS_SCEN_COUNT) || (scenario < SMI_BWC_SCEN_NORMAL)) {
  201. MMDVFSERR("invalid scenario\n");
  202. return -1;
  203. }
  204. /* go through all scenarios to decide the final step */
  205. scen_index = (int)scenario;
  206. spin_lock(&g_mmdvfs_mgr->scen_lock);
  207. g_mmdvfs_scenario_voltage[scen_index] = step;
  208. concurrency = 0;
  209. for (i = 0; i < MMDVFS_SCEN_COUNT; i++) {
  210. if (g_mmdvfs_scenario_voltage[i] == MMDVFS_VOLTAGE_HIGH)
  211. concurrency |= 1 << i;
  212. }
  213. /* one high = final high */
  214. for (i = 0; i < MMDVFS_SCEN_COUNT; i++) {
  215. if (g_mmdvfs_scenario_voltage[i] == MMDVFS_VOLTAGE_HIGH) {
  216. final_step = MMDVFS_VOLTAGE_HIGH;
  217. break;
  218. }
  219. }
  220. g_mmdvfs_current_step = final_step;
  221. spin_unlock(&g_mmdvfs_mgr->scen_lock);
  222. MMDVFSMSG("Set vol scen:%d,step:%d,final:%d(0x%x),CMD(%d,%d,0x%x),INFO(%d,%d)\n",
  223. scenario, step, final_step, concurrency,
  224. g_mmdvfs_cmd.sensor_size, g_mmdvfs_cmd.sensor_fps, g_mmdvfs_cmd.camera_mode,
  225. g_mmdvfs_info->video_record_size[0], g_mmdvfs_info->video_record_size[1]);
  226. #if MMDVFS_ENABLE
  227. /* call vcore dvfs API */
  228. if (final_step == MMDVFS_VOLTAGE_HIGH)
  229. vcorefs_request_dvfs_opp(KIR_MM, OPPI_PERF);
  230. else
  231. vcorefs_request_dvfs_opp(KIR_MM, OPPI_UNREQ);
  232. #endif
  233. return 0;
  234. }
  235. void mmdvfs_handle_cmd(MTK_MMDVFS_CMD *cmd)
  236. {
  237. #if !MMDVFS_ENABLE
  238. return;
  239. #endif
  240. MMDVFSMSG("MMDVFS cmd %u %d\n", cmd->type, cmd->scen);
  241. switch (cmd->type) {
  242. case MTK_MMDVFS_CMD_TYPE_MMSYS_SET:
  243. if (cmd->scen == SMI_BWC_SCEN_NORMAL) {
  244. mmdvfs_set_mmsys_clk(cmd->scen, MMSYS_CLK_LOW);
  245. vcorefs_request_dvfs_opp(KIR_MM, OPPI_UNREQ);
  246. } else {
  247. vcorefs_request_dvfs_opp(KIR_MM, OPPI_PERF);
  248. mmdvfs_set_mmsys_clk(cmd->scen, MMSYS_CLK_HIGH);
  249. }
  250. break;
  251. case MTK_MMDVFS_CMD_TYPE_SET:
  252. /* save cmd */
  253. mmdvfs_update_cmd(cmd);
  254. if (!(g_mmdvfs_concurrency & (1 << cmd->scen)))
  255. MMDVFSMSG("invalid set scen %d\n", cmd->scen);
  256. cmd->ret = mmdvfs_set_step(cmd->scen,
  257. mmdvfs_query(cmd->scen, cmd));
  258. break;
  259. case MTK_MMDVFS_CMD_TYPE_QUERY: { /* query with some parameters */
  260. if (mmdvfs_get_lcd_resolution() == MMDVFS_LCD_SIZE_FHD) {
  261. /* QUERY ALWAYS HIGH for FHD */
  262. cmd->ret = (unsigned int)MMDVFS_STEP_HIGH2HIGH;
  263. } else { /* FHD */
  264. mmdvfs_voltage_enum query_voltage = mmdvfs_query(cmd->scen, cmd);
  265. mmdvfs_voltage_enum current_voltage = mmdvfs_get_current_step();
  266. if (current_voltage < query_voltage) {
  267. cmd->ret = (unsigned int)MMDVFS_STEP_LOW2HIGH;
  268. } else if (current_voltage > query_voltage) {
  269. cmd->ret = (unsigned int)MMDVFS_STEP_HIGH2LOW;
  270. } else {
  271. cmd->ret
  272. = (unsigned int)(query_voltage
  273. == MMDVFS_VOLTAGE_HIGH
  274. ? MMDVFS_STEP_HIGH2HIGH
  275. : MMDVFS_STEP_LOW2LOW);
  276. }
  277. }
  278. MMDVFSMSG("query %d\n", cmd->ret);
  279. /* cmd->ret = (unsigned int)query_voltage; */
  280. break;
  281. }
  282. default:
  283. MMDVFSMSG("invalid mmdvfs cmd\n");
  284. BUG();
  285. break;
  286. }
  287. }
  288. void mmdvfs_notify_scenario_exit(MTK_SMI_BWC_SCEN scen)
  289. {
  290. #if !MMDVFS_ENABLE
  291. return;
  292. #endif
  293. MMDVFSMSG("leave %d\n", scen);
  294. #if !defined(SMI_D3) /* d3 does not need this workaround because the MMCLK is always the highest */
  295. /*
  296. * keep HPM for 4 seconds after exiting camera scenarios to get rid of
  297. * cam framework will let us go to normal scenario for a short time
  298. * (ex: STOP PREVIEW --> NORMAL --> START PREVIEW)
  299. * where the LPM mode (low MMCLK) may cause ISP failures
  300. */
  301. if ((scen == SMI_BWC_SCEN_VR) || (scen == SMI_BWC_SCEN_VR_SLOW)
  302. || (scen == SMI_BWC_SCEN_ICFP)) {
  303. mmdvfs_start_cam_monitor();
  304. }
  305. #endif /* !defined(SMI_D3) */
  306. /* reset scenario voltage to default when it exits */
  307. mmdvfs_set_step(scen, mmdvfs_get_default_step());
  308. }
  309. void mmdvfs_notify_scenario_enter(MTK_SMI_BWC_SCEN scen)
  310. {
  311. #if !MMDVFS_ENABLE
  312. return;
  313. #endif
  314. MMDVFSMSG("enter %d\n", scen);
  315. /* ISP ON = high */
  316. switch (scen) {
  317. #if defined(SMI_D2) /* d2 sensor > 6M */
  318. case SMI_BWC_SCEN_VR:
  319. mmdvfs_set_step(scen, mmdvfs_query(scen, NULL));
  320. break;
  321. #else /* default VR high */
  322. case SMI_BWC_SCEN_VR:
  323. #endif
  324. case SMI_BWC_SCEN_WFD:
  325. case SMI_BWC_SCEN_VR_SLOW:
  326. case SMI_BWC_SCEN_VSS:
  327. /* Fall through */
  328. case SMI_BWC_SCEN_ICFP:
  329. /* Fall through */
  330. case SMI_BWC_SCEN_FORCE_MMDVFS:
  331. mmdvfs_set_step(scen, MMDVFS_VOLTAGE_HIGH);
  332. break;
  333. default:
  334. break;
  335. }
  336. }
  337. void mmdvfs_init(MTK_SMI_BWC_MM_INFO *info)
  338. {
  339. #if !MMDVFS_ENABLE
  340. return;
  341. #endif
  342. spin_lock_init(&g_mmdvfs_mgr->scen_lock);
  343. /* set current step as the default step */
  344. g_mmdvfs_profile_id = mmdvfs_get_mmdvfs_profile();
  345. g_mmdvfs_current_step = mmdvfs_get_default_step();
  346. g_mmdvfs_info = info;
  347. }
  348. void mmdvfs_mhl_enable(int enable)
  349. {
  350. g_mmdvfs_mgr->is_mhl_enable = enable;
  351. }
  352. void mmdvfs_mjc_enable(int enable)
  353. {
  354. g_mmdvfs_mgr->is_mjc_enable = enable;
  355. }
  356. void mmdvfs_notify_scenario_concurrency(unsigned int u4Concurrency)
  357. {
  358. /* raise EMI monitor BW threshold in VP, VR, VR SLOW motion cases */
  359. /* to make sure vcore stay MMDVFS level as long as possible */
  360. if (u4Concurrency & ((1 << SMI_BWC_SCEN_VP) | (1 << SMI_BWC_SCEN_VR)
  361. | (1 << SMI_BWC_SCEN_VR_SLOW))) {
  362. #if MMDVFS_ENABLE_FLIPER_CONTROL
  363. MMDVFSMSG("fliper high\n");
  364. fliper_set_bw(BW_THRESHOLD_HIGH);
  365. #endif
  366. } else {
  367. #if MMDVFS_ENABLE_FLIPER_CONTROL
  368. MMDVFSMSG("fliper normal\n");
  369. fliper_restore_bw();
  370. #endif
  371. }
  372. g_mmdvfs_concurrency = u4Concurrency;
  373. }
  374. /* switch MM CLK callback from VCORE DVFS driver */
  375. void mmdvfs_mm_clock_switch_notify(int is_before, int is_to_high)
  376. {
  377. /* for WQHD 1.0v, we have to dynamically switch DL/DC */
  378. #ifdef MMDVFS_WQHD_1_0V
  379. int session_id;
  380. if (mmdvfs_get_lcd_resolution() != MMDVFS_LCD_SIZE_WQHD)
  381. return;
  382. session_id = MAKE_DISP_SESSION(DISP_SESSION_PRIMARY, 0);
  383. if (!is_before && is_to_high) {
  384. MMDVFSMSG("DL\n");
  385. /* nonblocking switch to direct link after HPM */
  386. primary_display_switch_mode_for_mmdvfs(DISP_SESSION_DIRECT_LINK_MODE, session_id,
  387. 0);
  388. } else if (is_before && !is_to_high) {
  389. /* BLOCKING switch to decouple before switching to LPM */
  390. MMDVFSMSG("DC\n");
  391. primary_display_switch_mode_for_mmdvfs(DISP_SESSION_DECOUPLE_MODE, session_id, 1);
  392. }
  393. #endif /* MMDVFS_WQHD_1_0V */
  394. }
  395. int mmdvfs_get_mmdvfs_profile(void)
  396. {
  397. int mmdvfs_profile_id = MMDVFS_PROFILE_UNKNOWN;
  398. unsigned int segment_code = 0;
  399. segment_code = _GET_BITS_VAL_(31 : 25, get_devinfo_with_index(47));
  400. #if defined(SMI_D1)
  401. mmdvfs_profile_id = MMDVFS_PROFILE_D1;
  402. if (segment_code == 0x41 || segment_code == 0x42 ||
  403. segment_code == 0x43 || segment_code == 0x49 ||
  404. segment_code == 0x51)
  405. mmdvfs_profile_id = MMDVFS_PROFILE_D1_PLUS;
  406. else
  407. mmdvfs_profile_id = MMDVFS_PROFILE_D1;
  408. #elif defined(SMI_D2)
  409. mmdvfs_profile_id = MMDVFS_PROFILE_D2;
  410. if (segment_code == 0x4A || segment_code == 0x4B)
  411. mmdvfs_profile_id = MMDVFS_PROFILE_D2_M_PLUS;
  412. else if (segment_code == 0x52 || segment_code == 0x53)
  413. mmdvfs_profile_id = MMDVFS_PROFILE_D2_P_PLUS;
  414. else
  415. mmdvfs_profile_id = MMDVFS_PROFILE_D2;
  416. #elif defined(SMI_D3)
  417. mmdvfs_profile_id = MMDVFS_PROFILE_D3;
  418. #elif defined(SMI_J)
  419. mmdvfs_profile_id = MMDVFS_PROFILE_J1;
  420. #elif defined(SMI_EV)
  421. mmdvfs_profile_id = MMDVFS_PROFILE_E1;
  422. #endif
  423. return mmdvfs_profile_id;
  424. }
  425. int is_mmdvfs_supported(void)
  426. {
  427. int mmdvfs_profile_id = mmdvfs_get_mmdvfs_profile();
  428. if (mmdvfs_profile_id == MMDVFS_PROFILE_D1 && mmdvfs_get_lcd_resolution() == MMDVFS_LCD_SIZE_FHD)
  429. return 0;
  430. else if (mmdvfs_profile_id == MMDVFS_PROFILE_UNKNOWN)
  431. return 0;
  432. else
  433. return 1;
  434. }
  435. static clk_switch_cb notify_cb_func = default_clk_switch_cb;
  436. static clk_switch_cb notify_cb_func_nolock;
  437. static vdec_ctrl_cb vdec_suspend_cb_func;
  438. static vdec_ctrl_cb vdec_resume_cb_func;
  439. int register_mmclk_switch_vdec_ctrl_cb(vdec_ctrl_cb vdec_suspend_cb,
  440. vdec_ctrl_cb vdec_resume_cb)
  441. {
  442. vdec_suspend_cb_func = vdec_suspend_cb;
  443. vdec_resume_cb_func = vdec_resume_cb;
  444. return 1;
  445. }
  446. int register_mmclk_switch_cb(clk_switch_cb notify_cb,
  447. clk_switch_cb notify_cb_nolock)
  448. {
  449. notify_cb_func = notify_cb;
  450. notify_cb_func_nolock = notify_cb_nolock;
  451. return 1;
  452. }
  453. /* This desing is only for CLK Mux switch relate flows */
  454. int mmdvfs_notify_mmclk_switch_request(int event)
  455. {
  456. /* This API should only be used in J1 MMDVFS profile */
  457. return 0;
  458. }
  459. static int mmdfvs_adjust_mmsys_clk_by_hopping(int clk_mode)
  460. {
  461. int result = 1;
  462. if (g_mmdvfs_profile_id != MMDVFS_PROFILE_D2_M_PLUS &&
  463. g_mmdvfs_profile_id != MMDVFS_PROFILE_D2_P_PLUS) {
  464. result = 0;
  465. return result;
  466. }
  467. if (!is_vcorefs_can_work()) {
  468. result = 0;
  469. return result;
  470. }
  471. if (clk_mode == MMSYS_CLK_HIGH) {
  472. if (current_mmsys_clk == MMSYS_CLK_MEDIUM)
  473. mt_dfs_vencpll(0xE0000);
  474. vdec_ctrl_func_checked(vdec_suspend_cb_func, "VDEC suspend");
  475. freqhopping_config(FH_VENC_PLLID , 0, false);
  476. notify_cb_func_checked(notify_cb_func, MMSYS_CLK_LOW, MMSYS_CLK_HIGH,
  477. "notify_cb_func");
  478. freqhopping_config(FH_VENC_PLLID , 0, true);
  479. vdec_ctrl_func_checked(vdec_resume_cb_func, "VDEC resume");
  480. current_mmsys_clk = MMSYS_CLK_HIGH;
  481. } else if (clk_mode == MMSYS_CLK_MEDIUM) {
  482. if (current_mmsys_clk == MMSYS_CLK_HIGH) {
  483. vdec_ctrl_func_checked(vdec_suspend_cb_func, "VDEC suspend");
  484. freqhopping_config(FH_VENC_PLLID , 0, false);
  485. notify_cb_func_checked(notify_cb_func, MMSYS_CLK_HIGH, MMSYS_CLK_LOW, "notify_cb_func");
  486. freqhopping_config(FH_VENC_PLLID , 0, true);
  487. vdec_ctrl_func_checked(vdec_resume_cb_func, "VDEC resume");
  488. }
  489. mt_dfs_vencpll(0x1713B1);
  490. notify_cb_func_checked(notify_cb_func, current_mmsys_clk, MMSYS_CLK_MEDIUM,
  491. "notify_cb_func");
  492. current_mmsys_clk = MMSYS_CLK_MEDIUM;
  493. } else if (clk_mode == MMSYS_CLK_LOW) {
  494. if (current_mmsys_clk == MMSYS_CLK_HIGH) {
  495. vdec_ctrl_func_checked(vdec_suspend_cb_func, "VDEC suspend");
  496. freqhopping_config(FH_VENC_PLLID , 0, false);
  497. notify_cb_func_checked(notify_cb_func, MMSYS_CLK_HIGH, MMSYS_CLK_LOW, "notify_cb_func");
  498. freqhopping_config(FH_VENC_PLLID , 0, true);
  499. vdec_ctrl_func_checked(vdec_resume_cb_func, "VDEC resume");
  500. }
  501. mt_dfs_vencpll(0xE0000);
  502. current_mmsys_clk = MMSYS_CLK_LOW;
  503. } else {
  504. MMDVFSMSG("Don't change CLK: mode=%d\n", clk_mode);
  505. result = 0;
  506. }
  507. return result;
  508. }
  509. int mmdvfs_set_mmsys_clk(MTK_SMI_BWC_SCEN scenario, int mmsys_clk_mode)
  510. {
  511. return mmdfvs_adjust_mmsys_clk_by_hopping(mmsys_clk_mode);
  512. }
  513. static int vdec_ctrl_func_checked(vdec_ctrl_cb func, char *msg)
  514. {
  515. if (func == NULL) {
  516. MMDVFSMSG("vdec_ctrl_func is NULL, not invoked: %s\n", msg);
  517. } else {
  518. func();
  519. return 1;
  520. }
  521. return 0;
  522. }
  523. static int notify_cb_func_checked(clk_switch_cb func, int ori_mmsys_clk_mode, int update_mmsys_clk_mode, char *msg)
  524. {
  525. if (func == NULL) {
  526. MMDVFSMSG("notify_cb_func is NULL, not invoked: %s, (%d,%d)\n", msg, ori_mmsys_clk_mode,
  527. update_mmsys_clk_mode);
  528. } else {
  529. if (ori_mmsys_clk_mode != update_mmsys_clk_mode)
  530. MMDVFSMSG("notify_cb_func: %s, (%d,%d)\n", msg, ori_mmsys_clk_mode, update_mmsys_clk_mode);
  531. func(ori_mmsys_clk_mode, update_mmsys_clk_mode);
  532. return 1;
  533. }
  534. return 0;
  535. }
  536. static int mmsys_clk_switch_impl(unsigned int venc_pll_con1_val)
  537. {
  538. if (g_mmdvfs_profile_id != MMDVFS_PROFILE_D2_M_PLUS
  539. && g_mmdvfs_profile_id != MMDVFS_PROFILE_D2_P_PLUS) {
  540. MMDVFSMSG("mmsys_clk_switch_impl is not support in profile:%d", g_mmdvfs_profile_id);
  541. return 0;
  542. }
  543. #if defined(SMI_D2)
  544. clkmux_sel(MT_MUX_MM, 6, "SMI common");
  545. mt_set_vencpll_con1(venc_pll_con1_val);
  546. udelay(20);
  547. clkmux_sel(MT_MUX_MM, 1, "SMI common");
  548. #endif
  549. return 1;
  550. }
  551. static int default_clk_switch_cb(int ori_mmsys_clk_mode, int update_mmsys_clk_mode)
  552. {
  553. unsigned int venc_pll_con1_val = 0;
  554. if (ori_mmsys_clk_mode == MMSYS_CLK_LOW && update_mmsys_clk_mode == MMSYS_CLK_HIGH) {
  555. if (g_mmdvfs_profile_id == MMDVFS_PROFILE_D2_M_PLUS)
  556. venc_pll_con1_val = 0x820F0000; /* 380MHz (35M+) */
  557. else
  558. venc_pll_con1_val = 0x82110000; /* 442MHz (35P+) */
  559. } else if (ori_mmsys_clk_mode == MMSYS_CLK_HIGH && update_mmsys_clk_mode == MMSYS_CLK_LOW) {
  560. venc_pll_con1_val = 0x830E0000;
  561. } else {
  562. MMDVFSMSG("default_clk_switch_cb: by-pass (%d,%d)\n", ori_mmsys_clk_mode, update_mmsys_clk_mode);
  563. return 1;
  564. }
  565. if (venc_pll_con1_val != 0)
  566. mmsys_clk_switch_impl(venc_pll_con1_val);
  567. return 1;
  568. }