aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos/sec-reboot.c
blob: b3c0b0aa762ed01734ed74363a716f8599fd506f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include <linux/delay.h>
#include <linux/pm.h>
#include <asm/io.h>
#include <asm/cacheflush.h>
#include <mach/system.h>
#include <mach/regs-pmu.h>
#include <mach/gpio.h>

/* charger cable state */
extern bool is_cable_attached;
#ifdef CONFIG_MACH_U1_NA_SPR
static void cdma_wimax_chk_modem_pwroff(void);
#endif
static void sec_power_off(void)
{
	int poweroff_try = 0;

	local_irq_disable();

	pr_emerg("%s : cable state=%d\n", __func__, is_cable_attached);

	while (1) {
#ifdef CONFIG_MACH_U1_NA_SPR
		cdma_wimax_chk_modem_pwroff();
#endif
		/* Check reboot charging */
		if (is_cable_attached || (poweroff_try >= 5)) {
			pr_emerg
			    ("%s: charger connected(%d) or power"
			     "off failed(%d), reboot!\n",
			     __func__, is_cable_attached, poweroff_try);
			writel(0x0, S5P_INFORM2);	/* To enter LP charging */

			flush_cache_all();
			outer_flush_all();
			arch_reset(0, 0);

			pr_emerg("%s: waiting for reboot\n", __func__);
			while (1);
		}

		/* wait for power button release */
		if (gpio_get_value(GPIO_nPOWER)) {
			pr_emerg("%s: set PS_HOLD low\n", __func__);

			/* power off code
			 * PS_HOLD Out/High -->
			 * Low PS_HOLD_CONTROL, R/W, 0x1002_330C
			 */
			writel(readl(S5P_PS_HOLD_CONTROL) & 0xFFFFFEFF,
			       S5P_PS_HOLD_CONTROL);

			++poweroff_try;
			pr_emerg
			    ("%s: Should not reach here! (poweroff_try:%d)\n",
			     __func__, poweroff_try);
		} else {
			/* if power button is not released, wait and check TA again */
			pr_info("%s: PowerButton is not released.\n", __func__);
		}
		mdelay(1000);
	}
}

#define REBOOT_MODE_PREFIX	0x12345670
#define REBOOT_MODE_NONE	0
#define REBOOT_MODE_DOWNLOAD	1
#define REBOOT_MODE_UPLOAD	2
#define REBOOT_MODE_CHARGING	3
#define REBOOT_MODE_RECOVERY	4
#define REBOOT_MODE_FOTA	5
#define REBOOT_MODE_FOTA_BL	6	/* update bootloader */

#define REBOOT_SET_PREFIX	0xabc00000
#define REBOOT_SET_DEBUG	0x000d0000
#define REBOOT_SET_SWSEL	0x000e0000
#define REBOOT_SET_SUD		0x000f0000

#ifdef CONFIG_MACH_U1_NA_SPR
static void cdma_wimax_chk_modem_pwroff(void)
{
	int phone_wait_cnt = 0;

	pr_emerg("%s\n", __func__);

	/* phone power off */
	gpio_direction_output(GPIO_QSC_PHONE_ON, GPIO_LEVEL_LOW);

	/*  confirm phone off */
	while (1) {
		if (gpio_get_value(GPIO_QSC_PHONE_ACTIVE)) {
			printk(KERN_ALERT"Try to Turn Phone Off by CP_RST\n");
			gpio_set_value(GPIO_QSC_PHONE_RST, 0);
			if (phone_wait_cnt > 10) {
				pr_emerg("%s: PHONE OFF Failed\n", __func__);
				break;
			}
			phone_wait_cnt++;
			mdelay(100);
		} else {
			pr_emerg("%s: PHONE OFF Success\n", __func__);
			break;
		}
	}
}
#endif
static void sec_reboot(char str, const char *cmd)
{
	local_irq_disable();

	pr_emerg("%s (%d, %s)\n", __func__, str, cmd ? cmd : "(null)");

	writel(0x12345678, S5P_INFORM2);	/* Don't enter lpm mode */

	if (!cmd) {
		writel(REBOOT_MODE_PREFIX | REBOOT_MODE_NONE, S5P_INFORM3);
	} else {
		unsigned long value;
		if (!strcmp(cmd, "fota"))
			writel(REBOOT_MODE_PREFIX | REBOOT_MODE_FOTA,
			       S5P_INFORM3);
		else if (!strcmp(cmd, "fota_bl"))
			writel(REBOOT_MODE_PREFIX | REBOOT_MODE_FOTA_BL,
			       S5P_INFORM3);
		else if (!strcmp(cmd, "recovery"))
			writel(REBOOT_MODE_PREFIX | REBOOT_MODE_RECOVERY,
			       S5P_INFORM3);
		else if (!strcmp(cmd, "bootloader"))
			writel(REBOOT_MODE_PREFIX | REBOOT_MODE_DOWNLOAD,
			       S5P_INFORM3);
		else if (!strcmp(cmd, "download"))
			writel(REBOOT_MODE_PREFIX | REBOOT_MODE_DOWNLOAD,
			       S5P_INFORM3);
		else if (!strcmp(cmd, "upload"))
			writel(REBOOT_MODE_PREFIX | REBOOT_MODE_UPLOAD,
			       S5P_INFORM3);
		else if (!strncmp(cmd, "debug", 5)
			 && !kstrtoul(cmd + 5, 0, &value))
			writel(REBOOT_SET_PREFIX | REBOOT_SET_DEBUG | value,
			       S5P_INFORM3);
		else if (!strncmp(cmd, "swsel", 5)
			 && !kstrtoul(cmd + 5, 0, &value))
			writel(REBOOT_SET_PREFIX | REBOOT_SET_SWSEL | value,
			       S5P_INFORM3);
		else if (!strncmp(cmd, "sud", 3)
			 && !kstrtoul(cmd + 3, 0, &value))
			writel(REBOOT_SET_PREFIX | REBOOT_SET_SUD | value,
			       S5P_INFORM3);
		else if (!strncmp(cmd, "emergency", 9))
			writel(0, S5P_INFORM3);
		else
			writel(REBOOT_MODE_PREFIX | REBOOT_MODE_NONE,
			       S5P_INFORM3);
	}

	flush_cache_all();
	outer_flush_all();
	arch_reset(0, 0);

	pr_emerg("%s: waiting for reboot\n", __func__);
	while (1);
}

static int __init sec_reboot_init(void)
{
	/* to support system shut down */
	pm_power_off = sec_power_off;
	arm_pm_restart = sec_reboot;
	return 0;
}

subsys_initcall(sec_reboot_init);