blob: 24cd26a2c0161e4d0ca4f75c58aee6c6e7da56e7 [file] [log] [blame]
Mahesh Sivasubramanianf2d6eb82011-11-22 16:33:48 -07001/* Copyright (c) 2011, 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:
112 if (!pdata->p_addr)
113 return -ENODEV;
114 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:
128 /*
129 * Set the boot remap address and enable remapping of
130 * reset vector
131 */
132 if (!pdata->p_addr || !pdata->v_addr)
133 return -ENODEV;
134
135 __raw_writel((pdata->p_addr | BOOT_REMAP_ENABLE),
136 pdata->v_addr);
137
138 ret = msm_pm_boot_reset_vector_init(__va(pdata->p_addr));
139
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -0600140 msm_pm_boot_before_pc
141 = msm_pm_config_rst_vector_before_pc;
142 msm_pm_boot_after_pc
143 = msm_pm_config_rst_vector_after_pc;
144 break;
145 default:
146 __WARN();
147 }
148
149 return ret;
150}