blob: 80e5a5542eaf3580bfbbe27c78a4a34bd12b1f39 [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;
Murali Nalajala41786ab2012-03-06 10:47:32 +0530104 unsigned long entry;
Murali Nalajalafeedeae2012-03-28 16:15:32 +0530105 void __iomem *warm_boot_ptr;
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600106
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -0600107 switch (pdata->mode) {
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600108 case MSM_PM_BOOT_CONFIG_TZ:
109 ret = msm_pm_tz_boot_init();
110 msm_pm_boot_before_pc = msm_pm_config_tz_before_pc;
111 msm_pm_boot_after_pc = NULL;
112 break;
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -0600113 case MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS:
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -0600114 pdata->v_addr = ioremap(pdata->p_addr, PAGE_SIZE);
115 /* Fall through */
116 case MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT:
117
118 if (!pdata->v_addr)
119 return -ENODEV;
120
121 ret = msm_pm_boot_reset_vector_init(pdata->v_addr);
122 msm_pm_boot_before_pc
123 = msm_pm_config_rst_vector_before_pc;
124 msm_pm_boot_after_pc
125 = msm_pm_config_rst_vector_after_pc;
126 break;
127 case MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR:
Murali Nalajala41786ab2012-03-06 10:47:32 +0530128 if (!cpu_is_msm8625()) {
Murali Nalajalafeedeae2012-03-28 16:15:32 +0530129 /*
130 * Set the boot remap address and enable remapping of
131 * reset vector
132 */
133 if (!pdata->p_addr || !pdata->v_addr)
134 return -ENODEV;
135
136 ret = msm_pm_boot_reset_vector_init(
137 __va(pdata->p_addr));
138
Murali Nalajala41786ab2012-03-06 10:47:32 +0530139 __raw_writel((pdata->p_addr | BOOT_REMAP_ENABLE),
140 pdata->v_addr);
141
142 msm_pm_boot_before_pc
143 = msm_pm_config_rst_vector_before_pc;
144 msm_pm_boot_after_pc
145 = msm_pm_config_rst_vector_after_pc;
146 } else {
Murali Nalajalafeedeae2012-03-28 16:15:32 +0530147 warm_boot_ptr = ioremap_nocache(
148 MSM8625_WARM_BOOT_PHYS, SZ_64);
149 ret = msm_pm_boot_reset_vector_init(warm_boot_ptr);
150
Murali Nalajala41786ab2012-03-06 10:47:32 +0530151 entry = virt_to_phys(msm_pm_boot_entry);
152
Murali Nalajalab99ce122012-03-21 00:40:40 +0530153 /* Below sequence is a work around for cores
154 * to come out of GDFS properly on 8625 target.
155 * On 8625 while cores coming out of GDFS observed
156 * the memory corruption at very first memory read.
157 */
158 msm_pm_reset_vector[0] = 0xE59F000C; /* ldr r0, 0x14 */
159 msm_pm_reset_vector[1] = 0xE59F1008; /* ldr r1, 0x14 */
160 msm_pm_reset_vector[2] = 0xE1500001; /* cmp r0, r1 */
161 msm_pm_reset_vector[3] = 0x1AFFFFFB; /* bne 0x0 */
162 msm_pm_reset_vector[4] = 0xE12FFF10; /* bx r0 */
163 msm_pm_reset_vector[5] = entry; /* 0x14 */
Murali Nalajala41786ab2012-03-06 10:47:32 +0530164
165 /* Here upper 16bits[16:31] used by CORE1
166 * lower 16bits[0:15] used by CORE0
167 */
Murali Nalajalafeedeae2012-03-28 16:15:32 +0530168 entry = (MSM8625_WARM_BOOT_PHYS |
169 ((MSM8625_WARM_BOOT_PHYS & 0xFFFF0000) >> 16));
Murali Nalajala41786ab2012-03-06 10:47:32 +0530170
171 /* write 'entry' to boot remapper register */
172 __raw_writel(entry, (pdata->v_addr +
173 MPA5_BOOT_REMAP_ADDR));
174
175 /* Enable boot remapper for C0 [bit:25th] */
176 __raw_writel(readl_relaxed(pdata->v_addr +
177 MPA5_CFG_CTL_REG) | BIT(25),
178 pdata->v_addr + MPA5_CFG_CTL_REG);
179
180 /* Enable boot remapper for C1 [bit:26th] */
181 __raw_writel(readl_relaxed(pdata->v_addr +
182 MPA5_CFG_CTL_REG) | BIT(26),
183 pdata->v_addr + MPA5_CFG_CTL_REG);
184
185 msm_pm_boot_before_pc = msm_pm_write_boot_vector;
186 }
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600187 break;
188 default:
189 __WARN();
190 }
191
192 return ret;
193}