2 * Lightsleep config for Spreadtrum.
4 * Copyright (C) 2015 Spreadtrum Ltd.
5 * Author: Icy Zhu <icy.zhu@spreadtrum.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/export.h>
15 #include <linux/sched.h>
17 #include <soc/sprd/hardware.h>
18 #include <soc/sprd/sci_glb_regs.h>
19 #include <soc/sprd/sci.h>
20 #include <soc/sprd/cpuidle.h>
22 #define INTC_IRQ_EN (0x0008)
23 #define INTC_IRQ_DIS (0x000C)
25 /* For MCU_SYS_SLEEP Prepare */
26 static BLOCKING_NOTIFIER_HEAD(sc_cpuidle_chain_head);
27 #if defined(CONFIG_ARCH_SCX35LT8)
28 static int light_sleep = 1;
29 static int trace_debug = 1;
31 static int light_sleep = 1;
32 static int trace_debug = 0;
34 static int test_power = 0;
35 static int mcu_sleep_debug = 0;
37 /* Enable Lightsleep Function */
38 module_param_named(light_sleep, light_sleep, int, S_IRUGO | S_IWUSR);
39 /* Used to trace32 debug, because the value of trace32 is jumpy-changing while DAP clock be gatenning */
40 module_param_named(trace_debug, trace_debug, int, S_IRUGO | S_IWUSR);
41 /* Used to lightsleep state power test,if test_power be set to 1, the system will keep lightsleep state until to press powerkey */
42 module_param_named(test_power, test_power, int, S_IRUGO | S_IWUSR);
43 /* Used to MCU_SYS_SLEEP debug */
44 module_param_named(mcu_sleep_debug, mcu_sleep_debug, int, S_IRUGO | S_IWUSR);
46 int register_sc_cpuidle_notifier(struct notifier_block *nb)
48 printk("*** %s, nb->notifier_call:%pf ***\n", __func__, nb->notifier_call);
49 return blocking_notifier_chain_register(&sc_cpuidle_chain_head, nb);
51 EXPORT_SYMBOL_GPL(register_sc_cpuidle_notifier);
53 int unregister_sc_cpuidle_notifier(struct notifier_block *nb)
55 return blocking_notifier_chain_unregister(&sc_cpuidle_chain_head, nb);
57 EXPORT_SYMBOL_GPL(unregister_sc_cpuidle_notifier);
59 int sc_cpuidle_notifier_call_chain(unsigned long val)
61 int ret = blocking_notifier_call_chain(&sc_cpuidle_chain_head, val, NULL);
62 return notifier_to_errno(ret);
64 EXPORT_SYMBOL_GPL(sc_cpuidle_notifier_call_chain);
66 void light_sleep_en(void)
71 /* Disable All INTC for test lightsleep power */
72 __raw_writel(0xffffffef, (void *)(SPRD_INT_BASE + INTC_IRQ_DIS));
73 __raw_writel(0xffffffff, (void *)(SPRD_INTC0_BASE + INTC_IRQ_DIS));
74 __raw_writel(0xffffffff, (void *)(SPRD_INTC1_BASE + INTC_IRQ_DIS));
75 __raw_writel(0xffffffff, (void *)(SPRD_INTC2_BASE + INTC_IRQ_DIS));
76 __raw_writel(0xffffffff, (void *)(SPRD_INTC3_BASE + INTC_IRQ_DIS));
79 sci_glb_set(REG_AP_AHB_APCPU_AUTO_GATE_EN, BIT_APCPU_AUTO_GATE_EN);
81 sci_glb_set(REG_AP_AHB_MCU_PAUSE, BIT_MCU_LIGHT_SLEEP_EN);
84 sci_glb_set(REG_AP_AHB_AP_SYS_AUTO_SLEEP_CFG, BIT_APCPU_DBG_AUTO_GATE_EN);
85 sci_glb_set(REG_AP_AHB_AP_SYS_AUTO_SLEEP_CFG, BIT_APCPU_TRACE_AUTO_GATE_EN);
87 sci_glb_clr(REG_AON_APB_APB_EB0, BIT_APCPU_DAP_EB);
89 /* MCU sys sleep prepare */
90 if (!(sci_glb_read(REG_AP_AHB_AHB_EB, -1UL) & BIT_DMA_EB)) {
91 error = sc_cpuidle_notifier_call_chain(SC_CPUIDLE_PREPARE);
93 sci_glb_clr(REG_AP_AHB_MCU_PAUSE, BIT_MCU_SYS_SLEEP_EN);
94 if (mcu_sleep_debug) {
95 printk("[CPUIDLE]<mcu_sleep_pre>could not set %s ... \n", __func__);
99 /* Enable MCU sys sleep */
100 sci_glb_set(REG_AP_AHB_MCU_PAUSE, BIT_MCU_SYS_SLEEP_EN);
104 EXPORT_SYMBOL_GPL(light_sleep_en);
106 void light_sleep_dis(void)
110 sci_glb_set(REG_AON_APB_APB_EB0, BIT_APCPU_DAP_EB);
111 sci_glb_clr(REG_AP_AHB_AP_SYS_AUTO_SLEEP_CFG, BIT_APCPU_DBG_AUTO_GATE_EN);
112 sci_glb_clr(REG_AP_AHB_AP_SYS_AUTO_SLEEP_CFG, BIT_APCPU_TRACE_AUTO_GATE_EN);
113 /* Disable MCU sys sleep */
116 sci_glb_set(SPRD_INT_BASE + INTC_IRQ_EN, BIT(14) | BIT(4) | BIT(2));
117 __raw_writel(0x0010000c, (void *)(SPRD_INTC0_BASE + INTC_IRQ_EN));
118 __raw_writel(0xf68f4cd0, (void *)(SPRD_INTC1_BASE + INTC_IRQ_EN));
119 __raw_writel(0x00500000, (void *)(SPRD_INTC2_BASE + INTC_IRQ_EN));
120 __raw_writel(0x11000000, (void *)(SPRD_INTC3_BASE + INTC_IRQ_EN));
124 EXPORT_SYMBOL_GPL(light_sleep_dis);
126 void __init light_sleep_init(void)
129 sci_glb_set(REG_AP_AHB_AP_SYS_AUTO_SLEEP_CFG, BIT_APCPU_CORE_AUTO_GATE_EN);
130 /* AP_AHB clock Auto gating while ap doesn't into mcu_sys_sleep */
131 sci_glb_set(REG_AP_AHB_AP_SYS_AUTO_SLEEP_CFG, BIT_AP_AHB_AUTO_GATE_EN);
132 /* For wakeup lightsleep */
133 sci_glb_set(REG_PMU_APB_AP_WAKEUP_POR_CFG, BIT_AP_WAKEUP_POR_N);
136 arch_initcall(light_sleep_init);