blob: 0de65a5aa9cd561c7cd192aaeb14e40b3f6d74c1 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/reboot.h>
19#include <linux/io.h>
20#include <linux/delay.h>
21#include <linux/pm.h>
22#include <linux/mfd/pmic8058.h>
23#include <linux/mfd/pmic8901.h>
Jeff Ohlstein28009a82011-07-25 19:21:26 -070024#include <linux/mfd/pm8xxx/misc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025
26#include <asm/mach-types.h>
27
28#include <mach/msm_iomap.h>
29#include <mach/restart.h>
30#include <mach/scm-io.h>
31#include <mach/socinfo.h>
32
33#define TCSR_WDT_CFG 0x30
34
35#define WDT0_RST (MSM_TMR0_BASE + 0x38)
36#define WDT0_EN (MSM_TMR0_BASE + 0x40)
37#define WDT0_BARK_TIME (MSM_TMR0_BASE + 0x4C)
38#define WDT0_BITE_TIME (MSM_TMR0_BASE + 0x5C)
39
40#define PSHOLD_CTL_SU (MSM_TLMM_BASE + 0x820)
41
42#define RESTART_REASON_ADDR 0x65C
43#define DLOAD_MODE_ADDR 0x0
44
45static int restart_mode;
46void *restart_reason;
47
48#ifdef CONFIG_MSM_DLOAD_MODE
49static int in_panic;
50static void *dload_mode_addr;
51
52/* Download mode master kill-switch */
53static int dload_set(const char *val, struct kernel_param *kp);
54static int download_mode = 1;
55module_param_call(download_mode, dload_set, param_get_int,
56 &download_mode, 0644);
57
58static int panic_prep_restart(struct notifier_block *this,
59 unsigned long event, void *ptr)
60{
61 in_panic = 1;
62 return NOTIFY_DONE;
63}
64
65static struct notifier_block panic_blk = {
66 .notifier_call = panic_prep_restart,
67};
68
69static void set_dload_mode(int on)
70{
71 if (dload_mode_addr) {
72 __raw_writel(on ? 0xE47B337D : 0, dload_mode_addr);
73 __raw_writel(on ? 0xCE14091A : 0,
74 dload_mode_addr + sizeof(unsigned int));
75 mb();
76 }
77}
78
79static int dload_set(const char *val, struct kernel_param *kp)
80{
81 int ret;
82 int old_val = download_mode;
83
84 ret = param_set_int(val, kp);
85
86 if (ret)
87 return ret;
88
89 /* If download_mode is not zero or one, ignore. */
90 if (download_mode >> 1) {
91 download_mode = old_val;
92 return -EINVAL;
93 }
94
95 set_dload_mode(download_mode);
96
97 return 0;
98}
99#else
100#define set_dload_mode(x) do {} while (0)
101#endif
102
103void msm_set_restart_mode(int mode)
104{
105 restart_mode = mode;
106}
107EXPORT_SYMBOL(msm_set_restart_mode);
108
109static void msm_power_off(void)
110{
111 printk(KERN_NOTICE "Powering off the SoC\n");
112#ifdef CONFIG_MSM_DLOAD_MODE
113 set_dload_mode(0);
114#endif
115 if (cpu_is_msm8x60()) {
116 pm8058_reset_pwr_off(0);
117 pm8901_reset_pwr_off(0);
118 }
Jeff Ohlstein28009a82011-07-25 19:21:26 -0700119 pm8xxx_reset_pwr_off(0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120 __raw_writel(0, PSHOLD_CTL_SU);
121 mdelay(10000);
122 printk(KERN_ERR "Powering off has failed\n");
123 return;
124}
125
126void arch_reset(char mode, const char *cmd)
127{
128
129#ifdef CONFIG_MSM_DLOAD_MODE
130
131 /* This looks like a normal reboot at this point. */
132 set_dload_mode(0);
133
134 /* Write download mode flags if we're panic'ing */
135 set_dload_mode(in_panic);
136
137 /* Write download mode flags if restart_mode says so */
138 if (restart_mode == RESTART_DLOAD)
139 set_dload_mode(1);
140
141 /* Kill download mode if master-kill switch is set */
142 if (!download_mode)
143 set_dload_mode(0);
144#endif
145
146 printk(KERN_NOTICE "Going down for restart now\n");
147
148 if (cpu_is_msm8x60())
149 pm8058_reset_pwr_off(1);
Jeff Ohlstein28009a82011-07-25 19:21:26 -0700150 pm8xxx_reset_pwr_off(1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151
152 if (cmd != NULL) {
153 if (!strncmp(cmd, "bootloader", 10)) {
154 __raw_writel(0x77665500, restart_reason);
155 } else if (!strncmp(cmd, "recovery", 8)) {
156 __raw_writel(0x77665502, restart_reason);
157 } else if (!strncmp(cmd, "oem-", 4)) {
158 unsigned long code;
159 code = simple_strtoul(cmd + 4, NULL, 16) & 0xff;
160 __raw_writel(0x6f656d00 | code, restart_reason);
161 } else {
162 __raw_writel(0x77665501, restart_reason);
163 }
164 }
165
166 __raw_writel(0, WDT0_EN);
167 if (!(machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())) {
168 mb();
169 __raw_writel(0, PSHOLD_CTL_SU); /* Actually reset the chip */
170 mdelay(5000);
171 pr_notice("PS_HOLD didn't work, falling back to watchdog\n");
172 }
173
174 __raw_writel(1, WDT0_RST);
175 __raw_writel(5*0x31F3, WDT0_BARK_TIME);
176 __raw_writel(0x31F3, WDT0_BITE_TIME);
Jeff Ohlstein7cab7ff2011-07-14 18:03:57 -0700177 __raw_writel(1, WDT0_EN);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700178 secure_writel(3, MSM_TCSR_BASE + TCSR_WDT_CFG);
179
180 mdelay(10000);
181 printk(KERN_ERR "Restarting has failed\n");
182}
183
184static int __init msm_restart_init(void)
185{
186#ifdef CONFIG_MSM_DLOAD_MODE
187 atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
188 dload_mode_addr = MSM_IMEM_BASE + DLOAD_MODE_ADDR;
189
190 /* Reset detection is switched on below.*/
191 set_dload_mode(1);
192#endif
193 restart_reason = MSM_IMEM_BASE + RESTART_REASON_ADDR;
194 pm_power_off = msm_power_off;
195
196 return 0;
197}
198
199late_initcall(msm_restart_init);