blob: ce09f9f3d767c634ce63dbdff075a8ec63da9061 [file] [log] [blame]
Sravan Kumar Ambapuramb22cf4d2012-01-02 21:45:04 +05301/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -06002 *
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/kernel.h>
16#include <linux/init.h>
17#include <linux/io.h>
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -060018#include <mach/msm_iomap.h>
19#include <mach/socinfo.h>
20#include <asm/mach-types.h>
21#include <asm/sizes.h>
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -060022#include "scm-boot.h"
23#include "idle.h"
24#include "pm-boot.h"
25
26static uint32_t *msm_pm_reset_vector;
27static uint32_t saved_vector[2];
28static void (*msm_pm_boot_before_pc)(unsigned int cpu, unsigned long entry);
29static void (*msm_pm_boot_after_pc)(unsigned int cpu);
30
31#ifdef CONFIG_MSM_SCM
32static int __init msm_pm_tz_boot_init(void)
33{
34 int flag = 0;
35 if (num_possible_cpus() == 1)
36 flag = SCM_FLAG_WARMBOOT_CPU0;
37 else if (num_possible_cpus() == 2)
38 flag = SCM_FLAG_WARMBOOT_CPU0 | SCM_FLAG_WARMBOOT_CPU1;
Joel King274621c2011-12-05 06:18:20 -080039 else if (num_possible_cpus() == 4)
40 flag = SCM_FLAG_WARMBOOT_CPU0 | SCM_FLAG_WARMBOOT_CPU1 |
41 SCM_FLAG_WARMBOOT_CPU2 | SCM_FLAG_WARMBOOT_CPU3;
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -060042 else
43 __WARN();
44
45 return scm_set_boot_addr((void *)virt_to_phys(msm_pm_boot_entry), flag);
46}
47
48static void msm_pm_config_tz_before_pc(unsigned int cpu,
49 unsigned long entry)
50{
51 msm_pm_write_boot_vector(cpu, entry);
52}
53#else
54static int __init msm_pm_tz_boot_init(void)
55{
56 return 0;
57};
58
59static inline void msm_pm_config_tz_before_pc(unsigned int cpu,
60 unsigned long entry) {}
61#endif
62
63static int __init msm_pm_boot_reset_vector_init(uint32_t *reset_vector)
64{
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -060065 if (!reset_vector)
66 return -ENODEV;
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -060067 msm_pm_reset_vector = reset_vector;
68 mb();
69
70 return 0;
71}
72
73static void msm_pm_config_rst_vector_before_pc(unsigned int cpu,
74 unsigned long entry)
75{
76 saved_vector[0] = msm_pm_reset_vector[0];
77 saved_vector[1] = msm_pm_reset_vector[1];
78 msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */
79 msm_pm_reset_vector[1] = entry;
80}
81
82static void msm_pm_config_rst_vector_after_pc(unsigned int cpu)
83{
84 msm_pm_reset_vector[0] = saved_vector[0];
85 msm_pm_reset_vector[1] = saved_vector[1];
86}
87
88void msm_pm_boot_config_before_pc(unsigned int cpu, unsigned long entry)
89{
90 if (msm_pm_boot_before_pc)
91 msm_pm_boot_before_pc(cpu, entry);
92}
93
94void msm_pm_boot_config_after_pc(unsigned int cpu)
95{
96 if (msm_pm_boot_after_pc)
97 msm_pm_boot_after_pc(cpu);
98}
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -060099#define BOOT_REMAP_ENABLE BIT(0)
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600100
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -0600101int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600102{
103 int ret = 0;
104
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -0600105 switch (pdata->mode) {
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600106 case MSM_PM_BOOT_CONFIG_TZ:
107 ret = msm_pm_tz_boot_init();
108 msm_pm_boot_before_pc = msm_pm_config_tz_before_pc;
109 msm_pm_boot_after_pc = NULL;
110 break;
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -0600111 case MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS:
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -0600112 pdata->v_addr = ioremap(pdata->p_addr, PAGE_SIZE);
113 /* Fall through */
114 case MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT:
115
116 if (!pdata->v_addr)
117 return -ENODEV;
118
119 ret = msm_pm_boot_reset_vector_init(pdata->v_addr);
120 msm_pm_boot_before_pc
121 = msm_pm_config_rst_vector_before_pc;
122 msm_pm_boot_after_pc
123 = msm_pm_config_rst_vector_after_pc;
124 break;
125 case MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR:
126 /*
127 * Set the boot remap address and enable remapping of
128 * reset vector
129 */
130 if (!pdata->p_addr || !pdata->v_addr)
131 return -ENODEV;
132
133 __raw_writel((pdata->p_addr | BOOT_REMAP_ENABLE),
134 pdata->v_addr);
135
136 ret = msm_pm_boot_reset_vector_init(__va(pdata->p_addr));
137
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600138 msm_pm_boot_before_pc
139 = msm_pm_config_rst_vector_before_pc;
140 msm_pm_boot_after_pc
141 = msm_pm_config_rst_vector_after_pc;
142 break;
143 default:
144 __WARN();
145 }
146
147 return ret;
148}