fliper.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #include <linux/proc_fs.h>
  2. #include <linux/sched.h>
  3. #include <linux/seq_file.h>
  4. #include <linux/kallsyms.h>
  5. #include <linux/utsname.h>
  6. #include <linux/module.h>
  7. #include <linux/moduleparam.h>
  8. #include <asm/uaccess.h>
  9. #include <linux/printk.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/suspend.h>
  12. #include <linux/timer.h>
  13. #include <linux/jiffies.h>
  14. #ifdef CONFIG_PM_AUTOSLEEP
  15. #include <linux/fb.h>
  16. #include <linux/notifier.h>
  17. #endif
  18. #include "mach/fliper.h"
  19. #include "mach/mt_mem_bw.h"
  20. #include <mt_vcore_dvfs.h>
  21. #define SEQ_printf(m, x...)\
  22. do {\
  23. if (m)\
  24. seq_printf(m, x);\
  25. else\
  26. pr_debug(x);\
  27. } while (0)
  28. #define X_ms 100
  29. #define Y_steps (2000/X_ms)
  30. #define BW_THRESHOLD 1500
  31. #define BW_THRESHOLD_MAX 9000
  32. #define BW_THRESHOLD_MIN 1000
  33. static int bw_threshold;
  34. static int fliper_enabled;
  35. static void enable_fliper(void);
  36. static void disable_fliper(void);
  37. static int vcore_high(void);
  38. static int vcore_low(void);
  39. extern unsigned int get_ddr_type(void)__attribute__((weak));
  40. /* define supported DRAM types */
  41. enum {
  42. LPDDR2 = 0,
  43. DDR3_16,
  44. DDR3_32,
  45. LPDDR3,
  46. mDDR,
  47. };
  48. static int fliper_debug;
  49. static ssize_t mt_fliper_write(struct file *filp, const char *ubuf,
  50. size_t cnt, loff_t *data)
  51. {
  52. char buf[64];
  53. unsigned long val;
  54. int ret;
  55. if (cnt >= sizeof(buf))
  56. return -EINVAL;
  57. if (copy_from_user(&buf, ubuf, cnt))
  58. return -EFAULT;
  59. buf[cnt] = 0;
  60. ret = kstrtoul(buf, 10, (unsigned long *)&val);
  61. if (ret < 0) {
  62. if (fliper_debug)
  63. pr_crit("\n<<SOC DVFS FLIPER>> no support change POWER_MODE\n");
  64. return cnt;
  65. }
  66. if (val == 1) {
  67. fliper_enabled = 1;
  68. enable_fliper();
  69. } else if (val == 0) {
  70. fliper_enabled = 0;
  71. disable_fliper();
  72. } else if (val == 3) {
  73. fliper_debug ^= 1;
  74. } else if (val == 4) {
  75. fliper_set_bw(0);
  76. fliper_set_bw(10000);
  77. fliper_set_bw(BW_THRESHOLD_HIGH);
  78. } else if (val == 5) {
  79. fliper_restore_bw();
  80. } else if (val == 6) {
  81. ret = vcore_high();
  82. pr_crit("\n<<SOC DVFS FLIPER>> Command flip to S(%d)\n", ret);
  83. } else if (val == 7) {
  84. ret = vcore_low();
  85. pr_crit("\n<<SOC DVFS FLIPER>> Command flip to E(%d)\n", ret);
  86. } else if (val == 8) {
  87. if (bw_threshold < 5000)
  88. bw_threshold += 250;
  89. pr_crit("\n<<SOC DVFS FLIPER>> Command Change EMI bandwidth threshold to %d MB/s\n", bw_threshold);
  90. } else if (val == 9) {
  91. if (bw_threshold > 500)
  92. bw_threshold -= 250;
  93. pr_crit("\n<<SOC DVFS FLIPER>> Command Change EMI bandwidth threshold to %d MB/s\n", bw_threshold);
  94. }
  95. pr_crit(" fliper option: %lu\n", val);
  96. return cnt;
  97. }
  98. static int mt_fliper_show(struct seq_file *m, void *v)
  99. {
  100. SEQ_printf(m, "----------------------------------------\n");
  101. SEQ_printf(m, "Fliper Enabled:%d, bw threshold:%d MB/s\n", fliper_enabled, bw_threshold);
  102. SEQ_printf(m, "----------------------------------------\n");
  103. return 0;
  104. }
  105. /*** Seq operation of mtprof ****/
  106. static int mt_fliper_open(struct inode *inode, struct file *file)
  107. {
  108. return single_open(file, mt_fliper_show, inode->i_private);
  109. }
  110. static const struct file_operations mt_fliper_fops = {
  111. .open = mt_fliper_open,
  112. .write = mt_fliper_write,
  113. .read = seq_read,
  114. .llseek = seq_lseek,
  115. .release = single_release,
  116. };
  117. /******* POWER PERF TRANSFORMER *********/
  118. #include <asm/div64.h>
  119. #include <mt_cpufreq.h>
  120. static void mt_power_pef_transfer(void);
  121. static DEFINE_TIMER(mt_pp_transfer_timer, (void *)mt_power_pef_transfer, 0, 0);
  122. static int pp_index;
  123. static void mt_power_pef_transfer_work(void);
  124. static DECLARE_WORK(mt_pp_work, (void *) mt_power_pef_transfer_work);
  125. static int vcore_high(void)
  126. {
  127. int ret = 0;
  128. ret = vcorefs_request_dvfs_opp(KIR_EMIBW, OPPI_PERF);
  129. return ret;
  130. }
  131. static int vcore_low(void)
  132. {
  133. int ret = 0;
  134. ret = vcorefs_request_dvfs_opp(KIR_EMIBW, OPPI_UNREQ);
  135. return ret;
  136. }
  137. static void mt_power_pef_transfer_work(void)
  138. {
  139. unsigned long long emi_bw = 0;
  140. int perf_mode = -1;
  141. int ret;
  142. unsigned long long t1, t2;
  143. t1 = 0; t2 = 0;
  144. /*Get EMI*/
  145. if (fliper_debug == 1) {
  146. t1 = sched_clock();
  147. emi_bw = get_mem_bw();
  148. t2 = sched_clock();
  149. } else
  150. emi_bw = get_mem_bw();
  151. if (emi_bw > bw_threshold)
  152. perf_mode = 1;
  153. if (perf_mode == 1) {
  154. if (pp_index == 0) {
  155. ret = vcore_high();
  156. pr_crit("\n<<SOC DVFS FLIPER>> flip to S(%d), %llu\n", ret, emi_bw);
  157. }
  158. pp_index = 1 << Y_steps;
  159. } else {
  160. if (pp_index == 1) {
  161. ret = vcore_low();
  162. pr_crit("\n<<SOC DVFS FLIPER>> flip to E(%d), %llu\n", ret, emi_bw);
  163. }
  164. pp_index = pp_index >> 1;
  165. }
  166. if (fliper_debug == 1)
  167. pr_crit("EMI:Rate:count:mode %6llu:%4d :%llu ns\n", emi_bw, pp_index, t2-t1);
  168. }
  169. int fliper_set_bw(int bw)
  170. {
  171. if (bw <= BW_THRESHOLD_MAX && bw >= BW_THRESHOLD_MIN) {
  172. pr_crit("\n<<SOC DVFS FLIPER>> Set bdw threshold %d -> %d\n", bw_threshold, bw);
  173. bw_threshold = bw;
  174. } else {
  175. pr_crit("\n<<SOC DVFS FLIPER>> Set bdw threshold Error: %d (MAX:%d, MIN:%d)\n"
  176. , bw, BW_THRESHOLD_MAX, BW_THRESHOLD_MIN);
  177. }
  178. return 0;
  179. }
  180. int fliper_restore_bw(void)
  181. {
  182. pr_crit("\n<<SOC DVFS FLIPER>> Restore bdw threshold %d -> %d\n", bw_threshold, BW_THRESHOLD);
  183. bw_threshold = BW_THRESHOLD;
  184. return 0;
  185. }
  186. static void enable_fliper(void)
  187. {
  188. pr_crit("fliper enable +++\n");
  189. mod_timer(&mt_pp_transfer_timer, jiffies + msecs_to_jiffies(X_ms));
  190. }
  191. static void disable_fliper(void)
  192. {
  193. pr_crit("fliper disable ---\n");
  194. del_timer(&mt_pp_transfer_timer);
  195. }
  196. static void mt_power_pef_transfer(void)
  197. {
  198. mod_timer(&mt_pp_transfer_timer, jiffies + msecs_to_jiffies(X_ms));
  199. schedule_work(&mt_pp_work);
  200. }
  201. #ifndef CONFIG_PM_AUTOSLEEP
  202. static int
  203. fliper_pm_callback(struct notifier_block *nb,
  204. unsigned long action, void *ptr)
  205. {
  206. int ret;
  207. switch (action) {
  208. case PM_SUSPEND_PREPARE:
  209. ret = vcore_low();
  210. pr_crit("\n<<SOC DVFS FLIPER>> Suspend and flip to E(%d)\n", ret);
  211. pp_index = 0;
  212. disable_fliper();
  213. break;
  214. case PM_HIBERNATION_PREPARE:
  215. break;
  216. case PM_POST_SUSPEND:
  217. if (fliper_enabled == 1)
  218. enable_fliper();
  219. else
  220. pr_crit("\n<<SOC DVFS FLIPER>> Resume enable flipper but flipper is disabled\n");
  221. break;
  222. case PM_POST_HIBERNATION:
  223. break;
  224. default:
  225. return NOTIFY_DONE;
  226. }
  227. return NOTIFY_OK;
  228. }
  229. #endif
  230. #ifdef CONFIG_PM_AUTOSLEEP
  231. static void fliper_early_suspend(void)
  232. {
  233. int ret;
  234. ret = vcore_low();
  235. pr_emerg("\n<<SOC DVFS FLIPER>> Early Suspend and flip to E(%d)\n", ret);
  236. pp_index = 0;
  237. disable_fliper();
  238. }
  239. static void fliper_late_resume(void)
  240. {
  241. pr_emerg("\n<<SOC DVFS FLIPER>> Late Resume\n");
  242. enable_fliper();
  243. }
  244. static int fliper_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *fb_evdata)
  245. {
  246. struct fb_event *evdata = fb_evdata;
  247. int blank;
  248. if (event != FB_EVENT_BLANK)
  249. return 0;
  250. blank = *(int *)evdata->data;
  251. switch (blank) {
  252. case FB_BLANK_UNBLANK:
  253. case FB_BLANK_NORMAL:
  254. fliper_late_resume();
  255. break;
  256. case FB_BLANK_VSYNC_SUSPEND:
  257. case FB_BLANK_HSYNC_SUSPEND:
  258. break;
  259. case FB_BLANK_POWERDOWN:
  260. fliper_early_suspend();
  261. break;
  262. default:
  263. return -EINVAL;
  264. }
  265. return 0;
  266. }
  267. static struct notifier_block fliper_fb_notif = {
  268. .notifier_call = fliper_fb_notifier_callback,
  269. };
  270. #endif
  271. /*-----------------------------------------------*/
  272. #define TIME_5SEC_IN_MS 5000
  273. static int __init init_fliper(void)
  274. {
  275. struct proc_dir_entry *pe;
  276. int ret = 0;
  277. pe = proc_create("fliper", 0664, NULL, &mt_fliper_fops);
  278. if (!pe)
  279. return -ENOMEM;
  280. bw_threshold = BW_THRESHOLD;
  281. pr_debug("prepare mt pp transfer: jiffies:%lu-->%lu\n", jiffies, jiffies + msecs_to_jiffies(TIME_5SEC_IN_MS));
  282. pr_debug("- next jiffies:%lu >>> %lu\n", jiffies, jiffies + msecs_to_jiffies(X_ms));
  283. mod_timer(&mt_pp_transfer_timer, jiffies + msecs_to_jiffies(TIME_5SEC_IN_MS));
  284. fliper_enabled = 1;
  285. #ifdef CONFIG_PM_AUTOSLEEP
  286. ret = fb_register_client(&fliper_fb_notif);
  287. if (ret)
  288. pr_err("\n<<SOC DVFS FLIPER>> register fb notifier, ret=%d\n", ret);
  289. #else
  290. pm_notifier(fliper_pm_callback, 0);
  291. #endif
  292. return 0;
  293. }
  294. late_initcall(init_fliper);