blob: 7039e7d7520c439c6d4669d6ded285b3d2fd3cfa [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
Steve Mucklec25a9362012-03-22 16:40:01 -070032static void msm_pm_write_boot_vector(unsigned int cpu, unsigned long address)
33{
34 msm_pm_boot_vector[cpu] = address;
35 clean_caches((unsigned long)&msm_pm_boot_vector[cpu],
36 sizeof(msm_pm_boot_vector[cpu]),
37 virt_to_phys(&msm_pm_boot_vector[cpu]));
38}
39
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -060040static int __init msm_pm_tz_boot_init(void)
41{
42 int flag = 0;
43 if (num_possible_cpus() == 1)
44 flag = SCM_FLAG_WARMBOOT_CPU0;
45 else if (num_possible_cpus() == 2)
46 flag = SCM_FLAG_WARMBOOT_CPU0 | SCM_FLAG_WARMBOOT_CPU1;
Joel King274621c2011-12-05 06:18:20 -080047 else if (num_possible_cpus() == 4)
48 flag = SCM_FLAG_WARMBOOT_CPU0 | SCM_FLAG_WARMBOOT_CPU1 |
49 SCM_FLAG_WARMBOOT_CPU2 | SCM_FLAG_WARMBOOT_CPU3;
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -060050 else
51 __WARN();
52
53 return scm_set_boot_addr((void *)virt_to_phys(msm_pm_boot_entry), flag);
54}
55
56static void msm_pm_config_tz_before_pc(unsigned int cpu,
57 unsigned long entry)
58{
59 msm_pm_write_boot_vector(cpu, entry);
60}
61#else
62static int __init msm_pm_tz_boot_init(void)
63{
64 return 0;
65};
66
67static inline void msm_pm_config_tz_before_pc(unsigned int cpu,
68 unsigned long entry) {}
69#endif
70
71static int __init msm_pm_boot_reset_vector_init(uint32_t *reset_vector)
72{
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -060073 if (!reset_vector)
74 return -ENODEV;
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -060075 msm_pm_reset_vector = reset_vector;
76 mb();
77
78 return 0;
79}
80
81static void msm_pm_config_rst_vector_before_pc(unsigned int cpu,
82 unsigned long entry)
83{
84 saved_vector[0] = msm_pm_reset_vector[0];
85 saved_vector[1] = msm_pm_reset_vector[1];
86 msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */
87 msm_pm_reset_vector[1] = entry;
88}
89
90static void msm_pm_config_rst_vector_after_pc(unsigned int cpu)
91{
92 msm_pm_reset_vector[0] = saved_vector[0];
93 msm_pm_reset_vector[1] = saved_vector[1];
94}
95
96void msm_pm_boot_config_before_pc(unsigned int cpu, unsigned long entry)
97{
98 if (msm_pm_boot_before_pc)
99 msm_pm_boot_before_pc(cpu, entry);
100}
101
102void msm_pm_boot_config_after_pc(unsigned int cpu)
103{
104 if (msm_pm_boot_after_pc)
105 msm_pm_boot_after_pc(cpu);
106}
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -0600107#define BOOT_REMAP_ENABLE BIT(0)
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600108
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -0600109int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600110{
111 int ret = 0;
Murali Nalajala41786ab2012-03-06 10:47:32 +0530112 unsigned long entry;
Murali Nalajalafeedeae2012-03-28 16:15:32 +0530113 void __iomem *warm_boot_ptr;
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600114
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -0600115 switch (pdata->mode) {
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600116 case MSM_PM_BOOT_CONFIG_TZ:
117 ret = msm_pm_tz_boot_init();
118 msm_pm_boot_before_pc = msm_pm_config_tz_before_pc;
119 msm_pm_boot_after_pc = NULL;
120 break;
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -0600121 case MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS:
Maheshkumar Sivasubramanianc6c55032011-10-25 16:01:32 -0600122 pdata->v_addr = ioremap(pdata->p_addr, PAGE_SIZE);
123 /* Fall through */
124 case MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT:
125
126 if (!pdata->v_addr)
127 return -ENODEV;
128
129 ret = msm_pm_boot_reset_vector_init(pdata->v_addr);
130 msm_pm_boot_before_pc
131 = msm_pm_config_rst_vector_before_pc;
132 msm_pm_boot_after_pc
133 = msm_pm_config_rst_vector_after_pc;
134 break;
135 case MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR:
Murali Nalajala41786ab2012-03-06 10:47:32 +0530136 if (!cpu_is_msm8625()) {
Olav Haugane6a0acd2012-04-05 09:29:12 -0700137 void *remapped;
138
Murali Nalajalafeedeae2012-03-28 16:15:32 +0530139 /*
140 * Set the boot remap address and enable remapping of
141 * reset vector
142 */
143 if (!pdata->p_addr || !pdata->v_addr)
144 return -ENODEV;
145
Olav Haugane6a0acd2012-04-05 09:29:12 -0700146 remapped = ioremap_nocache(pdata->p_addr, SZ_8);
147 ret = msm_pm_boot_reset_vector_init(remapped);
Murali Nalajalafeedeae2012-03-28 16:15:32 +0530148
Murali Nalajala41786ab2012-03-06 10:47:32 +0530149 __raw_writel((pdata->p_addr | BOOT_REMAP_ENABLE),
150 pdata->v_addr);
151
152 msm_pm_boot_before_pc
153 = msm_pm_config_rst_vector_before_pc;
154 msm_pm_boot_after_pc
155 = msm_pm_config_rst_vector_after_pc;
156 } else {
Murali Nalajalafeedeae2012-03-28 16:15:32 +0530157 warm_boot_ptr = ioremap_nocache(
158 MSM8625_WARM_BOOT_PHYS, SZ_64);
159 ret = msm_pm_boot_reset_vector_init(warm_boot_ptr);
160
Murali Nalajala41786ab2012-03-06 10:47:32 +0530161 entry = virt_to_phys(msm_pm_boot_entry);
162
Murali Nalajalab99ce122012-03-21 00:40:40 +0530163 /* Below sequence is a work around for cores
164 * to come out of GDFS properly on 8625 target.
165 * On 8625 while cores coming out of GDFS observed
166 * the memory corruption at very first memory read.
167 */
168 msm_pm_reset_vector[0] = 0xE59F000C; /* ldr r0, 0x14 */
169 msm_pm_reset_vector[1] = 0xE59F1008; /* ldr r1, 0x14 */
170 msm_pm_reset_vector[2] = 0xE1500001; /* cmp r0, r1 */
171 msm_pm_reset_vector[3] = 0x1AFFFFFB; /* bne 0x0 */
172 msm_pm_reset_vector[4] = 0xE12FFF10; /* bx r0 */
173 msm_pm_reset_vector[5] = entry; /* 0x14 */
Murali Nalajala41786ab2012-03-06 10:47:32 +0530174
175 /* Here upper 16bits[16:31] used by CORE1
176 * lower 16bits[0:15] used by CORE0
177 */
Murali Nalajalafeedeae2012-03-28 16:15:32 +0530178 entry = (MSM8625_WARM_BOOT_PHYS |
179 ((MSM8625_WARM_BOOT_PHYS & 0xFFFF0000) >> 16));
Murali Nalajala41786ab2012-03-06 10:47:32 +0530180
181 /* write 'entry' to boot remapper register */
182 __raw_writel(entry, (pdata->v_addr +
183 MPA5_BOOT_REMAP_ADDR));
184
185 /* Enable boot remapper for C0 [bit:25th] */
186 __raw_writel(readl_relaxed(pdata->v_addr +
187 MPA5_CFG_CTL_REG) | BIT(25),
188 pdata->v_addr + MPA5_CFG_CTL_REG);
189
190 /* Enable boot remapper for C1 [bit:26th] */
191 __raw_writel(readl_relaxed(pdata->v_addr +
192 MPA5_CFG_CTL_REG) | BIT(26),
193 pdata->v_addr + MPA5_CFG_CTL_REG);
Murali Nalajala41786ab2012-03-06 10:47:32 +0530194 }
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600195 break;
196 default:
197 __WARN();
198 }
199
200 return ret;
201}