import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm / mach-mt8127 / mt_idle.c
1 #define __MT_IDLE_C__
2
3 #include <linux/init.h>
4 #include <linux/kernel.h>
5 #include <linux/module.h>
6 #include <linux/cpu.h>
7
8 #include <linux/types.h>
9 #include <linux/string.h>
10 #include <mach/mt_cirq.h>
11 #include <asm/system_misc.h>
12
13 #include <mach/mt_typedefs.h>
14 #include <mach/sync_write.h>
15 #include <mach/mt_clkmgr.h>
16 #include <mach/mt_dcm.h>
17 #include <mach/mt_gpt.h>
18 #include <mach/mt_spm_idle.h>
19 #include <mach/mt_spm_sleep.h>
20 #include <mach/hotplug.h>
21 #include <mach/mt_cpufreq.h>
22 #include <mach/mt_power_gs.h>
23 #include <mach/mt_ptp.h>
24
25 #include <mach/mt_idle.h>
26
27 #define USING_XLOG
28
29 #ifdef USING_XLOG
30 #include <linux/xlog.h>
31
32 #define TAG "Power/swap"
33
34 #define idle_err(fmt, args...) \
35 xlog_printk(ANDROID_LOG_ERROR, TAG, fmt, ##args)
36 #define idle_warn(fmt, args...) \
37 xlog_printk(ANDROID_LOG_WARN, TAG, fmt, ##args)
38 #define idle_info(fmt, args...) \
39 xlog_printk(ANDROID_LOG_INFO, TAG, fmt, ##args)
40 #define idle_dbg(fmt, args...) \
41 xlog_printk(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
42 #define idle_ver(fmt, args...) \
43 xlog_printk(ANDROID_LOG_VERBOSE, TAG, fmt, ##args)
44
45 #else /* !USING_XLOG */
46
47 #define TAG "[Power/swap] "
48
49 #define idle_err(fmt, args...) \
50 pr_err(TAG fmt, ##args)
51 #define idle_warn(fmt, args...) \
52 pr_warn(TAG fmt, ##args)
53 #define idle_info(fmt, args...) \
54 pr_notice(TAG fmt, ##args)
55 #define idle_dbg(fmt, args...) \
56 pr_info(TAG fmt, ##args)
57 #define idle_ver(fmt, args...) \
58 pr_debug(TAG fmt, ##args)
59
60 #endif
61
62
63 #define idle_readl(addr) \
64 DRV_Reg32(addr)
65
66 #define idle_writel(addr, val) \
67 mt65xx_reg_sync_writel(val, addr)
68
69 #define idle_setl(addr, val) \
70 mt65xx_reg_sync_writel(idle_readl(addr) | (val), addr)
71
72 #define idle_clrl(addr, val) \
73 mt65xx_reg_sync_writel(idle_readl(addr) & ~(val), addr)
74
75
76 #define INVALID_GRP_ID(grp) (grp < 0 || grp >= NR_GRPS)
77 bool __attribute__((weak))
78 clkmgr_idle_can_enter(unsigned int *condition_mask, unsigned int *block_mask)
79 {
80 return false;
81 }
82
83 enum {
84 IDLE_TYPE_SO = 0,
85 IDLE_TYPE_DP = 1,
86 IDLE_TYPE_SL = 2,
87 IDLE_TYPE_RG = 3,
88 NR_TYPES = 4,
89 };
90
91 enum {
92 BY_CPU = 0,
93 BY_CLK = 1,
94 BY_TMR = 2,
95 BY_OTH = 3,
96 BY_VTG = 4,
97 NR_REASONS = 5
98 };
99
100 static const char *idle_name[NR_TYPES] = {
101 "soidle",
102 "dpidle",
103 "slidle",
104 "rgidle",
105 };
106
107 static const char *reason_name[NR_REASONS] = {
108 "by_cpu",
109 "by_clk",
110 "by_tmr",
111 "by_oth",
112 "by_vtg",
113 };
114
115 static int idle_switch[NR_TYPES] = {
116 1, /* soidle switch */
117 1, /* dpidle switch */
118 1, /* slidle switch */
119 1, /* rgidle switch */
120 };
121
122 /************************************************
123 * SODI part
124 ************************************************/
125 #ifdef SPM_SODI_ENABLED
126
127 static unsigned int soidle_gpt_percpu[NR_CPUS] = {
128 GPT4,
129 GPT1,
130 GPT4,
131 GPT5,
132 };
133
134 static unsigned int soidle_condition_mask[NR_GRPS] = {
135 0x11eee5c1, /* PERI0: */
136 0x00000007, /* PERI1: */
137 0x00000000, /* INFRA: */
138 0x00000000, /* TOPCK: */
139 0x000a4cc4, /* DISP0: */
140 0x00000000, /* DISP1: */
141 0x000003e1, /* IMAGE: */
142 0x00000001, /* MFG: */
143 0x00000040, /* AUDIO: */
144 0x00000000, /* VDEC0: */
145 0x00000001, /* VDEC1: */
146 };
147
148 static unsigned int soidle_block_mask[NR_GRPS] = {0x0};
149
150 static unsigned int soidle_timer_left[NR_CPUS];
151 static unsigned int soidle_timer_left2[NR_CPUS];
152 static unsigned int soidle_time_critera = 13000; /* 1ms */
153
154
155 static unsigned long soidle_cnt[NR_CPUS] = {0};
156 static unsigned long soidle_block_cnt[NR_CPUS][NR_REASONS] = { {0} };
157
158 static DEFINE_MUTEX(soidle_locked);
159
160 static void enable_soidle_by_mask(int grp, unsigned int mask)
161 {
162 mutex_lock(&soidle_locked);
163 soidle_condition_mask[grp] &= ~mask;
164 mutex_unlock(&soidle_locked);
165 }
166
167 static void disable_soidle_by_mask(int grp, unsigned int mask)
168 {
169 mutex_lock(&soidle_locked);
170 soidle_condition_mask[grp] |= mask;
171 mutex_unlock(&soidle_locked);
172 }
173
174 void enable_soidle_by_bit(int id)
175 {
176 int grp = clk_id_to_grp_id(id);
177 unsigned int mask = clk_id_to_mask(id);
178 BUG_ON(INVALID_GRP_ID(grp));
179 enable_soidle_by_mask(grp, mask);
180 }
181 EXPORT_SYMBOL(enable_soidle_by_bit);
182
183 void disable_soidle_by_bit(int id)
184 {
185 int grp = clk_id_to_grp_id(id);
186 unsigned int mask = clk_id_to_mask(id);
187 BUG_ON(INVALID_GRP_ID(grp));
188 disable_soidle_by_mask(grp, mask);
189 }
190 EXPORT_SYMBOL(disable_soidle_by_bit);
191
192
193 bool soidle_can_enter(int cpu)
194 {
195 int reason = NR_REASONS;
196
197 return false;
198
199 if (TRUE == gSpm_IsLcmVideoMode) {
200 reason = BY_OTH;
201 goto out;
202 }
203
204 if (gSPM_SODI_EN != 0) {
205 reason = BY_OTH;
206 goto out;
207 }
208
209 /*if hotplug-ing, can't enter sodi avoid bootslave corrupt*/
210 if (atomic_read(&is_in_hotplug) >= 1) {
211 reason = BY_CPU;
212 goto out;
213 }
214
215 if (atomic_read(&hotplug_cpu_count) != 1) {
216 reason = BY_CPU;
217 goto out;
218 }
219
220 if (cpu == 0) {
221 memset(soidle_block_mask, 0, NR_GRPS * sizeof(unsigned int));
222 if (!clkmgr_idle_can_enter(soidle_condition_mask, soidle_block_mask)) {
223 reason = BY_CLK;
224 goto out;
225 }
226 }
227
228 soidle_timer_left[cpu] = localtimer_get_counter();
229 if (soidle_timer_left[cpu] < soidle_time_critera ||
230 ((int)soidle_timer_left[cpu]) < 0) {
231 reason = BY_TMR;
232 goto out;
233 }
234
235 out:
236 if (reason < NR_REASONS) {
237 soidle_block_cnt[cpu][reason]++;
238 return false;
239 } else
240 return true;
241 }
242
243 void soidle_before_wfi(int cpu)
244 {
245 int err = 0;
246 unsigned int id = soidle_gpt_percpu[cpu];
247
248 free_gpt(id);
249 err = request_gpt(id, GPT_ONE_SHOT, GPT_CLK_SRC_SYS, GPT_CLK_DIV_1,
250 0, NULL, GPT_NOAUTOEN);
251 if (err)
252 idle_info("[%s]fail to request GPT4\n", __func__);
253
254 soidle_timer_left2[cpu] = localtimer_get_counter();
255
256
257 if ((int)soidle_timer_left2[cpu] <= 0)
258 gpt_set_cmp(id, 1); /* Trigger GPT4 Timerout imediately */
259 else
260 gpt_set_cmp(id, soidle_timer_left2[cpu]);
261
262 start_gpt(id);
263
264 }
265
266 void soidle_after_wfi(int cpu)
267 {
268 unsigned int id = soidle_gpt_percpu[cpu];
269
270 if (gpt_check_and_ack_irq(id))
271 localtimer_set_next_event(1);
272 else {
273 /* waked up by other wakeup source */
274 unsigned int cnt, cmp;
275 gpt_get_cnt(id, &cnt);
276 gpt_get_cmp(id, &cmp);
277 if (unlikely(cmp < cnt)) {
278 idle_err("[%s]GPT%d: counter = %10u, compare = %10u\n", __func__,
279 id + 1, cnt, cmp);
280 BUG();
281 }
282
283 localtimer_set_next_event(cmp-cnt);
284 stop_gpt(id);
285 }
286
287 soidle_cnt[cpu]++;
288 }
289
290 #endif /* SPM_SODI_ENABLED */
291
292 /************************************************
293 * deep idle part
294 ************************************************/
295 static unsigned int dpidle_condition_mask[NR_GRPS] = {
296 0x1bfd0ffd, /* PERI0: */
297 0x00000007, /* PERI1: */
298 0x0000a080, /* INFRA: */
299 0x00000000, /* TOPCK: */
300 0x001fffff, /* DISP0: */
301 0x00003fff, /* DISP1: */
302 0x000003e1, /* IMAGE: */
303 0x00000001, /* MFG: */
304 0x00000000, /* AUDIO: */
305 0x00000001, /* VDEC0: */
306 0x00000001, /* VDEC1: */
307 };
308
309 static unsigned int dpidle_block_mask[NR_GRPS] = {0x0};
310
311
312 static unsigned int dpidle_timer_left;
313 static unsigned int dpidle_timer_left2;
314 static unsigned int dpidle_time_critera = 26000;
315
316 static unsigned long dpidle_cnt[NR_CPUS] = {0};
317 static unsigned long dpidle_block_cnt[NR_REASONS] = {0};
318
319 static DEFINE_MUTEX(dpidle_locked);
320
321 static void enable_dpidle_by_mask(int grp, unsigned int mask)
322 {
323 mutex_lock(&dpidle_locked);
324 dpidle_condition_mask[grp] &= ~mask;
325 mutex_unlock(&dpidle_locked);
326 }
327
328 static void disable_dpidle_by_mask(int grp, unsigned int mask)
329 {
330 mutex_lock(&dpidle_locked);
331 dpidle_condition_mask[grp] |= mask;
332 mutex_unlock(&dpidle_locked);
333 }
334
335 void enable_dpidle_by_bit(int id)
336 {
337 int grp = clk_id_to_grp_id(id);
338 unsigned int mask = clk_id_to_mask(id);
339 BUG_ON(INVALID_GRP_ID(grp));
340 enable_dpidle_by_mask(grp, mask);
341 }
342 EXPORT_SYMBOL(enable_dpidle_by_bit);
343
344 void disable_dpidle_by_bit(int id)
345 {
346 int grp = clk_id_to_grp_id(id);
347 unsigned int mask = clk_id_to_mask(id);
348 BUG_ON(INVALID_GRP_ID(grp));
349 disable_dpidle_by_mask(grp, mask);
350 }
351 EXPORT_SYMBOL(disable_dpidle_by_bit);
352
353
354 static bool dpidle_can_enter(void)
355 {
356 int reason = NR_REASONS;
357
358 #ifdef SPM_SODI_ENABLED
359 if (gSPM_SODI_EN != 0) {
360 reason = BY_OTH;
361 goto out;
362 }
363 #endif
364
365 if (!mt_cpufreq_earlysuspend_status_get()) {
366 reason = BY_VTG;
367 goto out;
368 }
369
370 if (atomic_read(&hotplug_cpu_count) != 1) {
371 reason = BY_CPU;
372 goto out;
373 }
374
375 memset(dpidle_block_mask, 0, NR_GRPS * sizeof(unsigned int));
376 if (!clkmgr_idle_can_enter(dpidle_condition_mask, dpidle_block_mask)) {
377 reason = BY_CLK;
378 goto out;
379 }
380
381 dpidle_timer_left = localtimer_get_counter();
382 if (dpidle_timer_left < dpidle_time_critera ||
383 ((int)dpidle_timer_left) < 0) {
384 reason = BY_TMR;
385 goto out;
386 }
387
388 out:
389 if (reason < NR_REASONS) {
390 dpidle_block_cnt[reason]++;
391 return false;
392 } else
393 return true;
394 }
395
396 static unsigned int clk_cfg_3;
397
398 #define faudintbus_pll2sq() \
399 do { \
400 clk_cfg_3 = idle_readl(CLK_CFG_3); \
401 idle_writel(CLK_CFG_3, clk_cfg_3 & 0xF8FFFFFF); \
402 } while (0)
403
404 #define faudintbus_sq2pll() \
405 idle_writel(CLK_CFG_3, clk_cfg_3)
406
407
408 void spm_dpidle_before_wfi(void)
409 {
410
411 mt_power_gs_dump_dpidle();
412
413 bus_dcm_enable();
414
415 faudintbus_pll2sq();
416
417 #if 0
418 dpidle_timer_left = localtimer_get_counter();
419 gpt_set_cmp(GPT4, dpidle_timer_left);
420 #else
421 dpidle_timer_left2 = localtimer_get_counter();
422 gpt_set_cmp(GPT4, dpidle_timer_left2);
423 #endif
424 start_gpt(GPT4);
425
426 }
427
428 void spm_dpidle_after_wfi(void)
429 {
430 #if 0
431 idle_info("[%s]timer_left=%u, timer_left2=%u, delta=%u\n",
432 dpidle_timer_left, dpidle_timer_left2, dpidle_timer_left-dpidle_timer_left2);
433 #endif
434
435 if (gpt_check_and_ack_irq(GPT4)) {
436 /* waked up by WAKEUP_GPT */
437 localtimer_set_next_event(1);
438 } else {
439 /* waked up by other wakeup source */
440 unsigned int cnt, cmp;
441 gpt_get_cnt(GPT4, &cnt);
442 gpt_get_cmp(GPT4, &cmp);
443 if (unlikely(cmp < cnt)) {
444 idle_err("[%s]GPT%d: counter = %10u, compare = %10u\n", __func__,
445 GPT4 + 1, cnt, cmp);
446 BUG();
447 }
448
449 localtimer_set_next_event(cmp-cnt);
450 stop_gpt(GPT4);
451 }
452
453 faudintbus_sq2pll();
454
455 bus_dcm_disable();
456
457 dpidle_cnt[0]++;
458 }
459
460
461 /************************************************
462 * slow idle part
463 ************************************************/
464 static unsigned int slidle_condition_mask[NR_GRPS] = {
465 0x11e01000, /* PERI0: */
466 0x00000000, /* PERI1: */
467 0x00000000, /* INFRA: */
468 0x00000000, /* TOPCK: */
469 0x00000000, /* DISP0: */
470 0x00000000, /* DISP1: */
471 0x00000000, /* IMAGE: */
472 0x00000000, /* MFG: */
473 0x00000000, /* AUDIO: */
474 0x00000000, /* VDEC0: */
475 0x00000000, /* VDEC1: */
476 };
477 /* */
478 static unsigned int slidle_block_mask[NR_GRPS] = {0x0};
479
480 static unsigned long slidle_cnt[NR_CPUS] = {0};
481 static unsigned long slidle_block_cnt[NR_REASONS] = {0};
482
483 static DEFINE_MUTEX(slidle_locked);
484
485
486 static void enable_slidle_by_mask(int grp, unsigned int mask)
487 {
488 mutex_lock(&slidle_locked);
489 slidle_condition_mask[grp] &= ~mask;
490 mutex_unlock(&slidle_locked);
491 }
492
493 static void disable_slidle_by_mask(int grp, unsigned int mask)
494 {
495 mutex_lock(&slidle_locked);
496 slidle_condition_mask[grp] |= mask;
497 mutex_unlock(&slidle_locked);
498 }
499
500 void enable_slidle_by_bit(int id)
501 {
502 int grp = clk_id_to_grp_id(id);
503 unsigned int mask = clk_id_to_mask(id);
504 BUG_ON(INVALID_GRP_ID(grp));
505 enable_slidle_by_mask(grp, mask);
506 }
507 EXPORT_SYMBOL(enable_slidle_by_bit);
508
509 void disable_slidle_by_bit(int id)
510 {
511 int grp = clk_id_to_grp_id(id);
512 unsigned int mask = clk_id_to_mask(id);
513 BUG_ON(INVALID_GRP_ID(grp));
514 disable_slidle_by_mask(grp, mask);
515 }
516 EXPORT_SYMBOL(disable_slidle_by_bit);
517
518 static bool slidle_can_enter(void)
519 {
520 int reason = NR_REASONS;
521 if (atomic_read(&hotplug_cpu_count) != 1) {
522 reason = BY_CPU;
523 goto out;
524 }
525
526 memset(slidle_block_mask, 0, NR_GRPS * sizeof(unsigned int));
527 if (!clkmgr_idle_can_enter(slidle_condition_mask, slidle_block_mask)) {
528 reason = BY_CLK;
529 goto out;
530 }
531
532 #if EN_PTP_OD
533 if (ptp_data[0]) {
534 reason = BY_OTH;
535 goto out;
536 }
537 #endif
538
539 out:
540 if (reason < NR_REASONS) {
541 slidle_block_cnt[reason]++;
542 return false;
543 } else {
544 return true;
545 }
546 }
547
548 static void slidle_before_wfi(int cpu)
549 {
550 bus_dcm_enable();
551 }
552
553 static void slidle_after_wfi(int cpu)
554 {
555 bus_dcm_disable();
556
557 slidle_cnt[cpu]++;
558 }
559
560 static void go_to_slidle(int cpu)
561 {
562 slidle_before_wfi(cpu);
563
564 dsb();
565 __asm__ __volatile__("wfi" : : : "memory");
566
567 slidle_after_wfi(cpu);
568 }
569
570
571 /************************************************
572 * regular idle part
573 ************************************************/
574 static unsigned long rgidle_cnt[NR_CPUS] = {0};
575
576 static void rgidle_before_wfi(int cpu)
577 {
578 mt_power_gs_dump_idle();
579 }
580
581 static void rgidle_after_wfi(int cpu)
582 {
583 rgidle_cnt[cpu]++;
584 }
585
586 static noinline void go_to_rgidle(int cpu)
587 {
588 rgidle_before_wfi(cpu);
589
590 dsb();
591 __asm__ __volatile__("wfi" : : : "memory");
592
593 rgidle_after_wfi(cpu);
594 }
595
596 /************************************************
597 * idle task flow part
598 ************************************************/
599
600 /*
601 * xxidle_handler return 1 if enter and exit the low power state
602 */
603 #ifdef SPM_SODI_ENABLED
604
605 static int sodi_cpu_pdn = 1;
606 static inline int soidle_handler(int cpu)
607 {
608 if (idle_switch[IDLE_TYPE_SO]) {
609 if (soidle_can_enter(cpu)) {
610 spm_go_to_sodi(sodi_cpu_pdn);
611 return 1;
612 }
613 }
614
615 return 0;
616 }
617 #else
618 static inline int soidle_handler(int cpu)
619 {
620 return 0;
621 }
622 #endif
623
624 static int dpidle_cpu_pdn = 1;
625
626 static inline int dpidle_handler(int cpu)
627 {
628 int ret = 0;
629 if (idle_switch[IDLE_TYPE_DP]) {
630 if (dpidle_can_enter()) {
631 spm_go_to_dpidle(dpidle_cpu_pdn, 0);
632 ret = 1;
633 }
634 }
635
636 return ret;
637 }
638
639 static inline int slidle_handler(int cpu)
640 {
641 int ret = 0;
642 if (idle_switch[IDLE_TYPE_SL]) {
643 if (slidle_can_enter()) {
644 go_to_slidle(cpu);
645 ret = 1;
646 }
647 }
648
649 return ret;
650 }
651
652 static inline int rgidle_handler(int cpu)
653 {
654 int ret = 0;
655 if (idle_switch[IDLE_TYPE_RG]) {
656 go_to_rgidle(cpu);
657 ret = 1;
658 }
659
660 return ret;
661 }
662
663 static int (*idle_handlers[NR_TYPES])(int) = {
664 soidle_handler,
665 dpidle_handler,
666 slidle_handler,
667 rgidle_handler,
668 };
669
670
671 void arch_idle(void)
672 {
673 int cpu = smp_processor_id();
674 int i;
675
676 for (i = 0; i < NR_TYPES; i++) {
677 if (idle_handlers[i](cpu))
678 break;
679 }
680 }
681
682 #define idle_attr(_name) \
683 static struct kobj_attribute _name##_attr = { \
684 .attr = { \
685 .name = __stringify(_name), \
686 .mode = 0644, \
687 }, \
688 .show = _name##_show, \
689 .store = _name##_store, \
690 }
691
692
693 #ifdef SPM_SODI_ENABLED
694 static ssize_t soidle_state_show(struct kobject *kobj,
695 struct kobj_attribute *attr, char *buf)
696 {
697 int len = 0;
698 char *p = buf;
699
700 int cpus, reason, i;
701
702 p += sprintf(p, "*********** screen on idle state ************\n");
703 p += sprintf(p, "soidle_time_critera=%u\n", soidle_time_critera);
704
705 for (cpus = 0; cpus < nr_cpu_ids; cpus++) {
706 p += sprintf(p, "cpu:%d\n", cpus);
707 for (reason = 0; reason < NR_REASONS; reason++) {
708 p += sprintf(p, "[%d]soidle_block_cnt[%s]=%lu\n", reason,
709 reason_name[reason], soidle_block_cnt[cpus][reason]);
710 }
711 p += sprintf(p, "\n");
712 }
713
714 for (i = 0; i < NR_GRPS; i++) {
715 p += sprintf(p, "[%02d]soidle_condition_mask[%-8s]=0x%08x\t\tsoidle_block_mask[%-8s]=0x%08x\n", i,
716 grp_get_name(i), soidle_condition_mask[i],
717 grp_get_name(i), soidle_block_mask[i]);
718 }
719
720 p += sprintf(p, "\n********** soidle command help **********\n");
721 p += sprintf(p, "soidle help: cat /sys/power/soidle_state\n");
722 p += sprintf(p, "switch on/off: echo [soidle] 1/0 > /sys/power/soidle_state\n");
723 p += sprintf(p, "en_so_by_bit: echo enable id > /sys/power/soidle_state\n");
724 p += sprintf(p, "dis_so_by_bit: echo disable id > /sys/power/soidle_state\n");
725 p += sprintf(p, "modify tm_cri: echo time value(dec) > /sys/power/soidle_state\n");
726
727 len = p - buf;
728 return len;
729 }
730
731 static ssize_t soidle_state_store(struct kobject *kobj,
732 struct kobj_attribute *attr, const char *buf, size_t n)
733 {
734 char cmd[32];
735 int param;
736
737 if (sscanf(buf, "%s %d", cmd, &param) == 2) {
738 if (!strcmp(cmd, "soidle"))
739 idle_switch[IDLE_TYPE_SO] = param;
740 else if (!strcmp(cmd, "enable"))
741 enable_soidle_by_bit(param);
742 else if (!strcmp(cmd, "disable"))
743 disable_soidle_by_bit(param);
744 else if (!strcmp(cmd, "time"))
745 soidle_time_critera = param;
746
747 return n;
748 } else if (sscanf(buf, "%d", &param) == 1) {
749 idle_switch[IDLE_TYPE_SO] = param;
750 return n;
751 }
752
753 return -EINVAL;
754 }
755 idle_attr(soidle_state);
756 #endif
757
758 static ssize_t dpidle_state_show(struct kobject *kobj,
759 struct kobj_attribute *attr, char *buf)
760 {
761 int len = 0;
762 char *p = buf;
763
764 int i;
765
766 p += sprintf(p, "*********** deep idle state ************\n");
767 p += sprintf(p, "dpidle_cpu_pdn = %d\n", dpidle_cpu_pdn);
768 p += sprintf(p, "dpidle_time_critera=%u\n", dpidle_time_critera);
769
770 for (i = 0; i < NR_REASONS; i++) {
771 p += sprintf(p, "[%d]dpidle_block_cnt[%s]=%lu\n", i, reason_name[i],
772 dpidle_block_cnt[i]);
773 }
774
775 p += sprintf(p, "\n");
776
777 for (i = 0; i < NR_GRPS; i++) {
778 p += sprintf(p, "[%02d]dpidle_condition_mask[%-8s]=0x%08x\t\tdpidle_block_mask[%-8s]=0x%08x\n", i,
779 grp_get_name(i), dpidle_condition_mask[i],
780 grp_get_name(i), dpidle_block_mask[i]);
781 }
782
783 p += sprintf(p, "\n*********** dpidle command help ************\n");
784 p += sprintf(p, "dpidle help: cat /sys/power/dpidle_state\n");
785 p += sprintf(p, "switch on/off: echo [dpidle] 1/0 > /sys/power/dpidle_state\n");
786 p += sprintf(p, "cpupdn on/off: echo cpupdn 1/0 > /sys/power/dpidle_state\n");
787 p += sprintf(p, "en_dp_by_bit: echo enable id > /sys/power/dpidle_state\n");
788 p += sprintf(p, "dis_dp_by_bit: echo disable id > /sys/power/dpidle_state\n");
789 p += sprintf(p, "modify tm_cri: echo time value(dec) > /sys/power/dpidle_state\n");
790
791 len = p - buf;
792 return len;
793 }
794
795 static ssize_t dpidle_state_store(struct kobject *kobj,
796 struct kobj_attribute *attr, const char *buf, size_t n)
797 {
798 char cmd[32];
799 int param;
800
801 if (sscanf(buf, "%s %d", cmd, &param) == 2) {
802 if (!strcmp(cmd, "dpidle"))
803 idle_switch[IDLE_TYPE_DP] = param;
804 else if (!strcmp(cmd, "enable"))
805 enable_dpidle_by_bit(param);
806 else if (!strcmp(cmd, "disable"))
807 disable_dpidle_by_bit(param);
808 else if (!strcmp(cmd, "cpupdn"))
809 dpidle_cpu_pdn = !!param;
810 else if (!strcmp(cmd, "time"))
811 dpidle_time_critera = param;
812
813 return n;
814 } else if (sscanf(buf, "%d", &param) == 1) {
815 idle_switch[IDLE_TYPE_DP] = param;
816 return n;
817 }
818
819 return -EINVAL;
820 }
821 idle_attr(dpidle_state);
822
823 static ssize_t slidle_state_show(struct kobject *kobj,
824 struct kobj_attribute *attr, char *buf)
825 {
826 int len = 0;
827 char *p = buf;
828
829 int i;
830
831 p += sprintf(p, "*********** slow idle state ************\n");
832 for (i = 0; i < NR_REASONS; i++) {
833 p += sprintf(p, "[%d]slidle_block_cnt[%s]=%lu\n",
834 i, reason_name[i], slidle_block_cnt[i]);
835 }
836
837 p += sprintf(p, "\n");
838
839 for (i = 0; i < NR_GRPS; i++) {
840 p += sprintf(p, "[%02d]slidle_condition_mask[%-8s]=0x%08x\t\tslidle_block_mask[%-8s]=0x%08x\n", i,
841 grp_get_name(i), slidle_condition_mask[i],
842 grp_get_name(i), slidle_block_mask[i]);
843 }
844
845
846 p += sprintf(p, "\n********** slidle command help **********\n");
847 p += sprintf(p, "slidle help: cat /sys/power/slidle_state\n");
848 p += sprintf(p, "switch on/off: echo [slidle] 1/0 > /sys/power/slidle_state\n");
849
850 len = p - buf;
851 return len;
852 }
853
854 static ssize_t slidle_state_store(struct kobject *kobj,
855 struct kobj_attribute *attr, const char *buf, size_t n)
856 {
857 char cmd[32];
858 int param;
859
860 if (sscanf(buf, "%s %d", cmd, &param) == 2) {
861 if (!strcmp(cmd, "slidle"))
862 idle_switch[IDLE_TYPE_SL] = param;
863 else if (!strcmp(cmd, "enable"))
864 enable_slidle_by_bit(param);
865 else if (!strcmp(cmd, "disable"))
866 disable_slidle_by_bit(param);
867
868 return n;
869 } else if (sscanf(buf, "%d", &param) == 1) {
870 idle_switch[IDLE_TYPE_SL] = param;
871 return n;
872 }
873
874 return -EINVAL;
875 }
876 idle_attr(slidle_state);
877
878 static ssize_t rgidle_state_show(struct kobject *kobj,
879 struct kobj_attribute *attr, char *buf)
880 {
881 int len = 0;
882 char *p = buf;
883
884 p += sprintf(p, "*********** regular idle state ************\n");
885 p += sprintf(p, "\n********** rgidle command help **********\n");
886 p += sprintf(p, "rgidle help: cat /sys/power/rgidle_state\n");
887 p += sprintf(p, "switch on/off: echo [rgidle] 1/0 > /sys/power/rgidle_state\n");
888
889 len = p - buf;
890 return len;
891 }
892
893 static ssize_t rgidle_state_store(struct kobject *kobj,
894 struct kobj_attribute *attr, const char *buf, size_t n)
895 {
896 char cmd[32];
897 int param;
898
899 if (sscanf(buf, "%s %d", cmd, &param) == 2) {
900 if (!strcmp(cmd, "rgidle"))
901 idle_switch[IDLE_TYPE_RG] = param;
902
903 return n;
904 } else if (sscanf(buf, "%d", &param) == 1) {
905 idle_switch[IDLE_TYPE_RG] = param;
906 return n;
907 }
908
909 return -EINVAL;
910 }
911 idle_attr(rgidle_state);
912
913 static ssize_t idle_state_show(struct kobject *kobj,
914 struct kobj_attribute *attr, char *buf)
915 {
916 int len = 0;
917 char *p = buf;
918
919 int i;
920
921 p += sprintf(p, "********** idle state dump **********\n");
922 #ifdef SPM_SODI_ENABLED
923 for (i = 0; i < nr_cpu_ids; i++) {
924 p += sprintf(p, "soidle_cnt[%d]=%lu, dpidle_cnt[%d]=%lu, slidle_cnt[%d]=%lu, rgidle_cnt[%d]=%lu\n",
925 i, soidle_cnt[i], i, dpidle_cnt[i],
926 i, slidle_cnt[i], i, rgidle_cnt[i]);
927 }
928 #else
929 for (i = 0; i < nr_cpu_ids; i++) {
930 p += sprintf(p, "dpidle_cnt[%d]=%lu, slidle_cnt[%d]=%lu, rgidle_cnt[%d]=%lu\n",
931 i, dpidle_cnt[i], i, slidle_cnt[i], i, rgidle_cnt[i]);
932 }
933 #endif
934
935 p += sprintf(p, "\n********** variables dump **********\n");
936 for (i = 0; i < NR_TYPES; i++)
937 p += sprintf(p, "%s_switch=%d, ", idle_name[i], idle_switch[i]);
938 p += sprintf(p, "\n");
939
940 p += sprintf(p, "\n********** idle command help **********\n");
941 p += sprintf(p, "status help: cat /sys/power/idle_state\n");
942 p += sprintf(p, "switch on/off: echo switch mask > /sys/power/idle_state\n");
943
944 #ifdef SPM_SODI_ENABLED
945 p += sprintf(p, "soidle help: cat /sys/power/soidle_state\n");
946 #else
947 p += sprintf(p, "soidle help: soidle is unavailable\n");
948 #endif
949 p += sprintf(p, "dpidle help: cat /sys/power/dpidle_state\n");
950 p += sprintf(p, "slidle help: cat /sys/power/slidle_state\n");
951 p += sprintf(p, "rgidle help: cat /sys/power/rgidle_state\n");
952
953 len = p - buf;
954 return len;
955 }
956
957 static ssize_t idle_state_store(struct kobject *kobj,
958 struct kobj_attribute *attr, const char *buf, size_t n)
959 {
960 char cmd[32];
961 int idx;
962 int param;
963
964 if (sscanf(buf, "%s %x", cmd, &param) == 2) {
965 if (!strcmp(cmd, "switch")) {
966 for (idx = 0; idx < NR_TYPES; idx++) {
967 #ifndef SPM_SODI_ENABLED
968 if (idx == IDLE_TYPE_SO)
969 continue;
970 #endif
971 idle_switch[idx] = (param & (1U << idx)) ? 1 : 0;
972 }
973 }
974 return n;
975 }
976
977 return -EINVAL;
978 }
979 idle_attr(idle_state);
980
981
982 void mt_idle_init(void)
983 {
984 int err = 0;
985
986 idle_info("[%s]entry!!\n", __func__);
987 arm_pm_idle = arch_idle;
988
989 #ifndef SPM_SODI_ENABLED
990 idle_switch[IDLE_TYPE_SO] = 0;
991 #endif
992
993 err = free_gpt(GPT1);
994 if (err)
995 idle_info("[%s]fail to free GPT1\n", __func__);
996
997 err = request_gpt(GPT1, GPT_ONE_SHOT, GPT_CLK_SRC_SYS, GPT_CLK_DIV_1,
998 0, NULL, GPT_NOAUTOEN);
999 if (err)
1000 idle_info("[%s]fail to request GPT1\n", __func__);
1001
1002 err = request_gpt(GPT4, GPT_ONE_SHOT, GPT_CLK_SRC_SYS, GPT_CLK_DIV_1,
1003 0, NULL, GPT_NOAUTOEN);
1004 if (err)
1005 idle_info("[%s]fail to request GPT4\n", __func__);
1006
1007 err = request_gpt(GPT5, GPT_ONE_SHOT, GPT_CLK_SRC_SYS, GPT_CLK_DIV_1,
1008 0, NULL, GPT_NOAUTOEN);
1009 if (err)
1010 idle_info("[%s]fail to request GPT5\n", __func__);
1011
1012 err = sysfs_create_file(power_kobj, &idle_state_attr.attr);
1013 #ifdef SPM_SODI_ENABLED
1014 err |= sysfs_create_file(power_kobj, &soidle_state_attr.attr);
1015 #endif
1016 err |= sysfs_create_file(power_kobj, &dpidle_state_attr.attr);
1017 err |= sysfs_create_file(power_kobj, &slidle_state_attr.attr);
1018 err |= sysfs_create_file(power_kobj, &rgidle_state_attr.attr);
1019
1020 if (err)
1021 idle_err("[%s]: fail to create sysfs\n", __func__);
1022 }